I'm not too sure if I'm just completely forgetting basics here but can someone please tell me why after changing the flag only T1 stops?
#include <thread>
#include <iostream>
void job(const bool &flag)
{
using namespace std::chrono_literals;
while (flag)
{
std::cout << "Working T2" << '\n';
std::this_thread::sleep_for(1s);
}
}
int main(int argc, char const *argv[])
{
bool flag = true;
std::thread t1([&flag]()
{
using namespace std::chrono_literals;
while (flag)
{
std::cout << "Working T1" << '\n';
std::this_thread::sleep_for(1s);
}
});
std::thread t2(job, flag);
std::cin.get();
flag = false;
t1.join();
t2.join();
return 0;
}
my understanding is that both are accessing the same piece of memory as the flag is being passed as a reference, so the job function should not be creating it's own copy of the flag, and should just access the same flag passed to it, is this not how this works?
Many Thanks
std::thread t2(job, flag);
This makes a copy of flag and passes that copy to job(). In order to use a reference, you need to use std::ref:
std::thread t2(job, std::ref(flag));
But why is this a requirement?
There's a few different ways to look at it, but here's a fairly straightforward counter-example:
void job(const bool& val);
int main() {
// No problem
job(true);
// Would be broken if std::thread didn't make a copy.
std::thread my_thread(job, true);
}
Just so all the relevant information is in one place:
why after changing the flag only T1 stops?
Firstly, because std::thread copies its arguments by value, as you see from the linked documentation. So, the existing code is guaranteed not to work
If you fix this by wrapping the argument in std::ref as suggested, you reach the second problem (which is actually already present in your lambda version), which is:
Secondly because using this reference in another thread this way is a data race. So, the existing code is guaranteed not to be portable. It may happen to work for some platforms, some of the time, but it's still sloppy.
The flag should be a std::atomic<bool> (or std::atomic_flag) instead.
Related
Let's say I have this application:
#include <atomic>
#include <thread>
#include <iostream>
#include <chrono>
void do_something(const std::atomic<bool>& stop) {
while (!stop) {
std::cout << "Doing stuff..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main() {
std::atomic<bool> stop { false };
std::thread wait([&stop] {
std::this_thread::sleep_for(std::chrono::seconds(10));
stop = true;
});
do_something(stop);
wait.join();
}
This works as expected. The main thread loops until the wait thread sets stop. As far as I know, there's no real issues with this application since it's using an std::atomic<bool> for synchronization between the threads.
However, I can break the application by changing the signature of do_something to this:
void do_something(const bool& stop);
This still compiles without any warnings, but the loop in do_something never exits. Conceptually, I understand why this happens. do_something is accepting a const reference to a non-atomic value, so it would be reasonable to optimize the function to something like:
void do_something(const bool& stop) {
if (!stop) {
while(true) {
std::cout << "Doing stuff..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
}
What's confusing to me is why the modified application compiles at all. I wouldn't expect to be able to pass an std::atomic value into a function expecting a const reference to a non-atomic type. I haven't looked at the standard, but I don't see anything on cppreference that suggests this conversion is allowed.
Am I misunderstanding something here? Is this just some quirk of std::atomic that's not obvious to me from the documentation?
This is because there is an implicit conversion when you call
do_something(const bool &stop)
while passing an std::atomic<bool>
It translates to:
do_something(static_cast<bool>(stop.operator bool()));
As you can see here : https://en.cppreference.com/w/cpp/atomic/atomic/operator_T
You actually tell the compiler to load the value once, right at the time of the call.
I would like to synchronize different threads properly but so far I have only be able to write an inelegant solution. Can somebody kindly point out how I can improve the following code?
typedef void (*func)();
void thread(func func1, func func2, int& has_finished, int& id) {
has_finished--;
func1();
has_finished++;
while (has_finished != 0) std::cout << "thread " << id << " waiting\n";
std::cout << "thread" << id << "resuming\n";
func2();
}
int main() {
int has_finished(0), id_one(0), id_two(1);
std::thread t1(thread, fun, fun, std::ref(has_finished), std::ref(id_one));
std::thread t2(thread, fun, fun, std::ref(has_finished), std::ref(id_two));
t1.join();
t2.join();
};
The gist of the program is described by the function thread. The function is executed by two std::threads. The function accepts two long-running functions func1 and func2 and two references of ints as arguments. The threads should only invoke func2 after all threads exited func1. The argument has_finished is used to coordinate the different threads: Upon entering the function, has_arguments is zero. Then each std::thread decrements the value and invokes the long-running function func1. After having left func1, has_finished is incremented again. As long as this value is not at its original value of zero a thread waits. Then, each thread works on func2. The main function is shown at the end.
How can I coordinate the two threads better? I was thinking of using a std::mutex and std::condition_variable but could not figure out how to use them properly? Does somebody have any idea how I can improve the program?
Don't write this yourself. This kind of synchronization is known as a "latch" (or more generally a "barrier", and it's available through various libraries and through the C++ Concurrency TS. (It might also make it into C++20 in some form.)
For example, using a version from Boost:
#include <iostream>
#include <thread>
#include <boost/thread/latch.hpp>
void f(boost::latch& c) {
std::cout << "Doing work in round 1\n";
c.count_down_and_wait();
std::cout << "Doing work in round 2\n";
}
int main() {
boost::latch c(2);
std::thread t1(f, std::ref(c)), t2(f, std::ref(c));
t1.join();
t2.join();
}
The method you've chosen won't actually work and results in undefined behavior because of the race conditions. As you surmised, you need a condition variable.
Here is a Gate class demonstrating how to use a condition variable to implement a gate that waits for some number of threads to arrive at it before continuing:
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <sstream>
#include <utility>
#include <cassert>
struct Gate {
public:
explicit Gate(unsigned int count = 2) : count_(count) { } // How many threads need to reach the gate before it unlocks
Gate(Gate const &) = delete;
void operator =(Gate const &) = delete;
void wait_for_gate();
private:
int count_;
::std::mutex count_mutex_;
::std::condition_variable count_gate_;
};
void Gate::wait_for_gate()
{
::std::unique_lock<::std::mutex> guard(count_mutex_);
assert(count > 0); // Count being 0 here indicates an irrecoverable programming error.
--count_;
count_gate_.wait(guard, [this](){ return this-> count_ <= 0; });
guard.unlock();
count_gate_.notify_all();
}
void f1()
{
::std::ostringstream msg;
msg << "In f1 with thread " << ::std::this_thread::get_id() << '\n';
::std::cout << msg.str();
}
void f2()
{
::std::ostringstream msg;
msg << "In f2 with thread " << ::std::this_thread::get_id() << '\n';
::std::cout << msg.str();
}
void thread_func(Gate &gate)
{
f1();
gate.wait_for_gate();
f2();
}
int main()
{
Gate gate;
::std::thread t1{thread_func, ::std::ref(gate)};
::std::thread t2{thread_func, ::std::ref(gate)};
t1.join();
t2.join();
}
Hopefully the structure of this code looks enough like your code that you can understand what's going on here. From reading your code, it seems like you're looking for all threads to execute func1, then func2. You do not want func2 running while any thread is executing func1.
That can be thought of as a gate where all the threads are waiting to arrive at the 'finished func1' location before moving on to run func2.
I tested this code on my own local version of compiler explorer.
The main disadvantage of the latch in the other answer is that it is not yet standard C++. My Gate class is a simple implementation of the latch class mentioned in the other answer, and it is standard C++.
The basic way a condition variable works is that it unlocks a mutex, waits for a notify, then locks that mutex and tests the condition. If the condition is true, it continues without unlocking the mutex. If the condition is false, it starts over again.
So, after the condition variable says the condition is true, you have to do whatever you need to do, then unlock the mutex and notify everybody that you've done it.
The mutex here is guarding the shared count variable. Whenever you have a shared value you should guard it with a mutex so that no thread can see that value in an inconsistent state. The condition is that threads can wait for that count to reach 0, indicating that all threads have decremented the count variable.
I have following code which works in debug build not in the release build with g++ optimizations turned on. (When I say work, what I mean is when the main thread sets the flag stop to true, the looping thread exists).I know this issue can be fixed by adding volatile keyword. My question however is to understand what exactly is happening in this case. This is the code:
void main() {
bool stop = false;
std::thread reader_thread;
auto reader = [&]() {
std::cout << "starting reader" << std::endl;
//BindToCPU(reader_thread, 0);
while(!stop) {
}
std::cout << "exiting reader" << std::endl;
};
reader_thread = std::thread(reader);
sleep(2);
stop = true;
std::cout << "stopped" << std::endl;
reader_thread.join();
}
Why does this happen? Is it because compiler optimizations? Or is it because cache coherency issues? Some details on what exactly happens underneath is appreciated.
The behavior of the program is undefined. The problem is that two threads are both accessing the variable named stop, and one of them is writing to it. In the C++ standard, that's the definition of a data race, and the result is undefined behavior. To get rid of the data race you have to introduce synchronization in some form. The simplest way to do this is to change the type of stop from bool to std::atomic<bool>. Alternatively, you could use a mutex, but for this particular example, that would be overkill.
Marking stop as volatile might make the symptoms go away, but it does not fix the problem.
The problem is that the compiler, specifically the optimization phase cannot tell that the program actually does anything. In particular, it cannot tell that "stop" can ever be anything except false. The best and simplest solution is to make "stop" atomic. Here is the corrected program, with a bonus "sleep" routine at no extra charge.
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
inline void std_sleep(long double seconds) noexcept
{
using duration_t = std::chrono::duration<long long, std::nano>;
const auto duration = duration_t(static_cast<long long> (seconds * 1e9));
std::this_thread::sleep_for(duration);
}
int main() {
std::atomic<bool> stop = false;
std::thread reader_thread;
auto reader = [&stop]() {
std::cout << "starting reader" << std::endl;
//BindToCPU(reader_thread, 0);
while(!stop) {
std_sleep(.25);
}
std::cout << "exiting reader" << std::endl;
};
reader_thread = std::thread(reader);
std_sleep(2.0);
stop = true;
std::cout << "stopped" << std::endl;
reader_thread.join();
return 0;
}
You have several threads which access the same variable, and one of them writes to the variable. This situation is called a data race. A data race is undefined behavior, and compilers tend to do funny/catastrophic things in these cases.
One example, which happens to match your description, is stated in here in section 2.3:
... violate the compiler's assumption that ordinary variables do not change without being assigned to ... If the variable is not annotated at all,
the loop waiting for another thread to set flag:
while (!flag) {}
could even be transformed to the, now likely infinite, but sequentially equivalent, loop:
tmp = flag; // tmp is local
while (!tmp) {}
Another article about this type of race condition is this one.
I have no idea why my code doesn't terminate.
It is probably some obvious thing I miss here, please help!
using namespace std;
int main(int argc, char* argv[])
{
MyClass *m = new MyClass();
thread t1(th,m);
delete m;
m=NULL;
t1.join();
return 0;
}
void th(MyClass *&p)
{
while(p!=NULL)
{
cout << "tick" << endl;
this_thread::sleep_for(chrono::seconds(1));
}
return;
}
The thread is being given a copy of m, not a reference to it. Use a reference wrapper to give it a reference:
thread t1(th,std::ref(m));
The program will probably end as expected then; but you still have undefined behaviour due to the data race of modifying m on one thread, and reading it on another without synchronisation. To fix that, either use std::atomic<MyClass*>, or protect both accesses with a mutex.
enablePrint = (bool)someArgv; //set via argv in some code, don't worry about this
if (enablePrint) {
std::thread PrinterT(&Printer, 1000);}
//some code that does some stuff
if (enablePrint) {
PrinterT.join();}
produces:
compile error 194:9: error: ‘PrinterT’ was not declared in this scope PrinterT.join();}
I'm aware this is caused by the C++ requirement to declare PrinterT outside of an if block, what I don't know how to do is how do I declare PrinterT without causing it to automatically execute the function code in the thread? I want to be able to make the running of the Printer function contingent on whether it's enabled or not.
std::thread has an operator = that will do the trick. It moves a running thread into another thread variable.
The default constructor will create a std::thread variable that isn't really a thread.
Try something like:
enablePrint = (bool)someArgv; //set via argv in some code, don't worry about this
std::thread PrinterT;
if (enablePrint) {
PrinterT = std::thread(&Printer, 1000);}
//some code that does some stuff
if (enablePrint) {
PrinterT.join();}
Yes, use default std::thread constructor and move semantics.
thread(): http://ru.cppreference.com/w/cpp/thread/thread/thread
operator=(thread&&): http://en.cppreference.com/w/cpp/thread/thread/operator%3D
Example:
#include <iostream>
#include <thread>
int main() {
bool flag = true;
std::thread thread;
if (flag) {
thread = std::thread([]() {
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
std::cout << "Thread done\n";
});
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "Main done\n";
if (flag) {
thread.join();
}
return 0;
}