Search code examples
c++c++20waitnotifystdatomic

std::atomic::notify_one could unblock multiple threads


According to cppreference, std::atomic<T>::notify_one() will notify at least one thread that is waiting on said atomic. This means that according to the standard it could unblock more than one thread. This is in contrast to std::condition_variable::notify_one(), which specifies that it will unblock (no more than) one thread.

Where does this difference come from? Does this not use the same underlying mechanism? As far as implementations of the standard library go, do all of the prevalent ones have a chance of actually unblocking multiple with this call, or are there some that always unblock exactly one?


Solution

  • Both std::atomic::wait and std::condition_variable::wait are allowed to unblock spuriously at any time, including at the specific time that notify_one is called.

    So in terms of the specification, although it does indeed seem that the standard uses different wording for the two ("at least one" in [atomics.types.operation]/32 but just "one" in [thread.condition.condvar]/5), I don't think there is any normative difference here. The implementation is free to unblock any number of threads for both waiting operations when notify_one is called, as long as it is at least one (if any are waiting). This is true for std::atomic::notify_one as well as std::condition_variable::notify_one (i.e. "(no more than)" is wrong).


    In an earlier revision of the proposal [P1135R4] for the std::atomic waiting operations it still said "one" instead of "at least one" in the proposed wording.

    That was changed with revision [P1135R5], according to which wording improvements were made partly in response to feedback from LWG teleconferences. I don't think any documentation of these teleconferences is publicly available, so I can't tell whether there was a specific intent in this wording change.

    Maybe it is supposed to avoid misunderstandings since the spurious unblocking is mentioned in a different paragraph or maybe it is meant to convey that there are implementations which do unblock multiple/all waiting operations that are specifically intended to be supported as such. See also comments under the question and this answer.