How is std::atomic<T>::notify_all ordered?

空扰寡人 提交于 2020-07-06 13:55:48

问题


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:

  1. The program may hang, I must use fences to prevent it. What exactly fences, where and why?
  2. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!