Reputation: 33
An atomic bool "ready" is shared between two threads. Thread A is doing some task, and thread B is waiting to be notified by A. A will set "ready" to True when the task is complete.
B has a wait-predicate that tests "ready". On waking, if "ready" is still False, B will go back to waiting. (This prevents spurious wakes from causing trouble)
A finishes its task, sets "ready" to True, then notifies B.
Question: How can I guarantee B will read (load) "ready" as True and not the older False?
atomic<bool> ready = false;
Thread A
do_something();
ready = true;
B_cond_var.notify_one();
Thread B:
B_cond_var.wait( mtx, []() -> bool { return ready == true; } );
do_something(); // <- sometimes doesn't happen
I have found that sometimes B reads "ready" as False, and never wakes. Which means from its point of view the notify came before the update, even though in A the order is update, then notify.
NOTES: I have read entirely too much about memory ordering guarantees, and I think I understand enough about read and write ordering. However this question involves the ordering of memory updates and thread communication events, namely notify. I can't find a straight answer about how to guarantee ordering of these.
See eg: http://www.developerfusion.com/article/138018/memory-ordering-for-atomic-operations-in-c0x/
http://bartoszmilewski.com/2008/12/01/c-atomics-and-memory-ordering/
Memory ordering behavior of std::atomic::load
Also see C++11 standard section 29.3
UPDATE: Sorry for the confusion, the above is pseudocode only, boiled down from a much larger body and I have omitted things that don't enter into the problem such as the existence of a mutex on the condition variable. The working code exhibits the described reordering of variable update and notify roughly once every 400 days of runtime -- making it 3-4 per day in practice. This is actually happening.
Upvotes: 3
Views: 685
Reputation: 62603
You do not need atomic variable if you are protecting it with condition variable. However, condition variables require mutexes, and I do not see mutexes in this code. Your lambda missess return statement as well.
Properly used condition variables will give you result you want.
Memory ordering is completely irrelevant here, since all Posix thread synchronization primitives impose full memory barriers.
Upvotes: 2