How to use a std::condition_variable correctly?
c++, concurrency, condition-variable, multithreading
Solution
Typically you'd have some observable shared state on whose change you block:
bool done = false;
std::mutex done_mx;
std::condition_variable done_cv;
{
std::unique_lock<std::mutex> lock(done_mx);
std::thread worker([&]() {
// ...
std::lock_guard<std::mutex> lock(done_mx);
done = true;
done_cv.notify_one();
});
while (true) { done_cv.wait(lock); if (done) break; }
// ready, do other work
worker.join();
}
Note that you wait in a loop until the actual condition is met. Note also that access to the actual shared state (`done`) is serialized via the mutex `done_mx`, which is locked whenever `done` is accessed.
There's a helper member function that performs the condition check for you so you don't need the loop:
done_cv.wait(lock, [&]() { return done; });
Problem
I'm confused about `conditions_variables` and how to use them (safely). In my application I've a class that makes a gui-thread but while the gui is constructed by the gui-thread, the main thread needs to wait. The situation is the same as for the function below. The main thread makes a mutex, lock and `condition_variable`. It then makes the thread. While this `worker` `thread` has not passed a certain point (here printing the numbers), the main thread is not allowed to continue (i.e. has to `wait` for all numbers being printed). How do I use `condition_variables` correctly in this context? Also, I've read that spontaneous wake-ups are an issue. How can I handle them? ``` int main() { std::mutex mtx; std::unique_lock<std::mutex> lck(mtx); std::condition_variable convar; auto worker = std::thread([&]{ /* Do some work. Main-thread can not continue. */ for(int i=0; i<100; ++i) std::cout<<i<<" "; convar.notify_all(); // let main thread continue std::cout<<"\nworker done"<<std::endl; }); // The main thread can do some work but then must wait until the worker has done it's calculations. /* do some stuff */ convar.wait(lck); std::cout<<"\nmain can continue"<<std::endl; // allowed before worker is entirely finished worker.join(); } ```