Date: Mon, 18 Jul 2022 19:44:03 +0300
On 7/18/22 17:48, Nate Eldredge via Std-Discussion wrote:
> A question came up on StackOverflow regarding the Standard's language on
> atomic wait and notify operations
> (https://stackoverflow.com/questions/70228390/c20-how-is-the-returning-from-atomicwait-guaranteed-by-the-standard/70230293#70230293,
> asked by user zwhconst).
>
> Consider the following simple test case:
>
> std::atomic<bool> b{false};
>
> void thr1() {
> b.store(true, std::memory_order_relaxed);
> b.notify_one();
> }
>
> int main() {
> std::thread t(thr1);
> b.wait(false);
> t.join();
> return 0;
> }
>
> Presumably the standard's intention is that this program is guaranteed
> to terminate. But as currently worded, I cannot seem to prove it.
>
> Suppose that `b.wait(false)` starts while the value of `b` is still
> `false`, and so it blocks. When `b.notify_one()` executes, the main
> thread will unblock and test the value of `b`. However, I cannot find
> anything to clearly imply that the store of `true` to `b` will be
> visible by then. If the main thread loads the old value `false`, it
> will block again, and potentially never wake up (unless there is a
> spurious unblock).
What you're saying is only possible if notify_one is observed before the
store by the main thread. And that is not possible as the store is
sequenced-before the notify. Consequently, the store happens-before the
notify:
http://eel.is/c++draft/intro.multithread#intro.races-10
> Intuitively, I would think that `notify_one()` ought to synchronize with
> the corresponding unblock in `wait()`, but the standard doesn't seem to
> actually say so.
Synchronizes-with is a different relation that describes memory ordering
wrt. other objects than the atomic. Notifying operations don't do that
and don't need to do that because the preceding store does that. I.e. it
is the store that may synchronize-with the load performed by the waiting
operation.
> A question came up on StackOverflow regarding the Standard's language on
> atomic wait and notify operations
> (https://stackoverflow.com/questions/70228390/c20-how-is-the-returning-from-atomicwait-guaranteed-by-the-standard/70230293#70230293,
> asked by user zwhconst).
>
> Consider the following simple test case:
>
> std::atomic<bool> b{false};
>
> void thr1() {
> b.store(true, std::memory_order_relaxed);
> b.notify_one();
> }
>
> int main() {
> std::thread t(thr1);
> b.wait(false);
> t.join();
> return 0;
> }
>
> Presumably the standard's intention is that this program is guaranteed
> to terminate. But as currently worded, I cannot seem to prove it.
>
> Suppose that `b.wait(false)` starts while the value of `b` is still
> `false`, and so it blocks. When `b.notify_one()` executes, the main
> thread will unblock and test the value of `b`. However, I cannot find
> anything to clearly imply that the store of `true` to `b` will be
> visible by then. If the main thread loads the old value `false`, it
> will block again, and potentially never wake up (unless there is a
> spurious unblock).
What you're saying is only possible if notify_one is observed before the
store by the main thread. And that is not possible as the store is
sequenced-before the notify. Consequently, the store happens-before the
notify:
http://eel.is/c++draft/intro.multithread#intro.races-10
> Intuitively, I would think that `notify_one()` ought to synchronize with
> the corresponding unblock in `wait()`, but the standard doesn't seem to
> actually say so.
Synchronizes-with is a different relation that describes memory ordering
wrt. other objects than the atomic. Notifying operations don't do that
and don't need to do that because the preceding store does that. I.e. it
is the store that may synchronize-with the load performed by the waiting
operation.
Received on 2022-07-18 16:44:07