Search code examples
c++multithreadingatomicc++20stdatomic

Call the notify_all method after store with release memory order on an atomic


I have the following code being executed on a single thread (written in C++20):

std::atomic_bool is_ready{};

void SetReady() {
  is_ready.store(true, std::memory_order_release);
  is_ready.notify_all();
}

Other threads execute the text listed below:

void Wait() {
  is_ready.wait(false, std::memory_order_acquire);
}

As I know, release memory order doesn't ensure that the operations located after it will not be reordered by a compiler. So, can I place notify_all() after store() with release memory order? Is it safe? Just I have some thoughts that store() may be sequenced before notify_all() and hence may not be reordered.


Solution

  • The memory orders are irrelevant here. They only affect ordering of memory access other than on the atomic itself and you have none.

    The compiler cannot reorder the notify_all call before the store in any case, because notify_all is specified to wake up all waiting operations on the atomic which are eligible to be unblocked.

    Which these are depends on whether, in the global modification order of the atomic, the last store which happens-before the call to notify_all is ordered after the store observed by the waiting thread when it blocked.

    In your shown code the true store is sequenced-before the notify_all call (in the same thread), which implies that the store happens-before the call, but if the lines were switched, then that wouldn't be the case anymore.

    Moving the notify_all before the store would thus potentially change the set of waiting operations which are eligible to be unblocked.

    If the compiler was allowed to do that, then the waiting/notification mechanism would be pretty useless. This is also the same as for other operations on the same atomic in the same thread (or really any operations on the same storage location in the same thread). The compiler cannot reorder these either.

    So yes, it is safe and the Wait thread will not wait forever. (I am assuming that the initialization std::atomic_bool is_ready{}; is happening before either of the shown thread functions start execution.)