问题
I expect the below program not to hang.
If (2) and (3) are observed in reverse order in (1), it may hang due to lost notification:
#include <atomic>
#include <chrono>
#include <thread>
int main()
{
std::atomic<bool> go{ false };
std::thread thd([&go] {
go.wait(false, std::memory_order_relaxed); // (1)
});
std::this_thread::sleep_for(std::chrono::milliseconds(400));
go.store(true, std::memory_order_relaxed); // (2)
go.notify_all(); // (3)
thd.join();
return 0;
}
So the question is what would happen here:
- The program may hang, I must use fences to prevent it. What exactly fences, where and why?
- The program may not hang. Then how mentioned reordering is prevented? I'm not asking about implementations, I'm asking about standard wording.
回答1:
The standard states:
A call to an atomic waiting operation on an atomic object M is eligible to be unblocked by a call to an atomic notifying operation on M if there exist side effects X and Y on M such that:
- the atomic waiting operation has blocked after observing the result of X,
- X precedes Y in the modification order of M, and
- Y happens before the call to the atomic notifying operation.
And about nofify_all
:
Effects: Unblocks the execution of all atomic waiting operations on
*ptr
that are eligible to be unblocked by this call.
In your example the initialization of go
(M) corresponds to X, and the store
(2) to Y. The initialization happens-before the call to wait, and the store happens-before the call to notify. The store happens-before the notify because it is sequenced-before it, and both functions operate on the same object. It doesn't matter that the store itself is relaxed, since the memory order only orders surrounding operations. [intro.races] 6.9.2.1.19 states:
The [..] coherence requirements effectively disallow compiler reordering of atomic operations to a single object, even if both operations are relaxed loads. This effectively makes the cache coherence guarantee provided by most hardware available to C++ atomic operations.
Unfortunately the standard is rather vague regarding visibility, but as I understand it, a wait call that is unblocked by some notify call is guaranteed to observe the latest change that happened-before that notify call (or some later value) - just like it is the case for condition variables
So no, your program cannot hang.
来源:https://stackoverflow.com/questions/62295310/how-is-stdatomictnotify-all-ordered