I am reading aboutstd::condition_variable and I don't understand this:
Even if the shared variable is atomic, it must be modified under the mutex in order to correctly publish the modification to the waiting thread.
Why a shared atomic variable is not properly published if it is not modified under mutex? How to understand this statement?
The following quote fromstd::atomic<T>) seems to contradict to the the above statement:
If one thread writes to an atomic object while another thread reads from it, the behavior is well-defined (see memory model for details on data races).
- 1
std::condition_variableandstd::atomicare two different things.πάντα ῥεῖ– πάντα ῥεῖ2016-07-01 14:30:32 +00:00CommentedJul 1, 2016 at 14:30 - 1I suppose it's because the waiting thread synchronizes via the mutex (otherwise it couldn't be "waiting") and not via the atomic variable.Kerrek SB– Kerrek SB2016-07-01 14:30:34 +00:00CommentedJul 1, 2016 at 14:30
- 5It's about the final example instackoverflow.com/a/32978267/2756719T.C.– T.C.2016-07-01 14:33:17 +00:00CommentedJul 1, 2016 at 14:33
- Well if the
std::condition_variablehas any other internal state then that needs to be protected(synchronized).NathanOliver– NathanOliver2016-07-01 14:33:40 +00:00CommentedJul 1, 2016 at 14:33 - Atomicity does not necessarily means synchronized. Seeshan-weiqiang.github.io/2024/04/27/…shan– shan2024-04-27 11:49:38 +00:00CommentedApr 27, 2024 at 11:49
1 Answer1
Consider this example:
std::atomic_bool proceed = false;std::mutex m;std::condition_variable cv;std::thread t([&m,&cv,&proceed](){ std::unique_lock<std::mutex> l(m); while(!proceed) { hardWork(); cv.wait(l); }});proceed = true;cv.notify_one();t.join();Here the atomic shared dataproceed is modified without the use of a mutex, after which notification is sent to the condition variable. But it is possible that at the instant that the notification is sent, the threadt is not waiting oncv: instead it is insidehardWork() having checkedproceed just before that and found it to be false. The notification is missed. Whent completeshardWork, it will resume the wait (presumably forever).
Had the main thread locked the mutex before modifying the shared dataproceed, the situation would have been avoided.
I think this is the situation in mind when saying "Even if the shared variable is atomic, it must be modified under the mutex in order to correctly publish the modification to the waiting thread."
9 Comments
hardWork. You can checkproceed, find it to be false, thenproceed can be set totrue, thennotify_one can be called, and then you can callwait. Again, you'd be waiting for something that already happened. The entire logic of condition variables is that they work in conjunction with the mutex that protects the shared state to provide an atomic "unlock and wait" operation.lock_guard{m} betweenproceed = true; andcv.notify_one();? If do that,notify_one will not be called beforewait.proceed is atomic or not because it is never accessed without holding the mutex.proceed and then unlocking it again directly, before signalling the CV