Quantcast
Channel: How do I synchronize a store before a load in multiple threads? - Stack Overflow
Viewing all articles
Browse latest Browse all 2

How do I synchronize a store before a load in multiple threads?

$
0
0

Consider the following program:

#include <thread>#include <atomic>#include <cassert>int x = 0;std::atomic<int> y = {0};std::atomic<bool> x_was_zero = {false};std::atomic<bool> y_was_zero = {false};void write_x_load_y(){    x = 1;    if (y == 0)        y_was_zero = true;}void write_y_load_x(){    y = 1;    if (x == 0)        x_was_zero = true;}int main(){    std::thread a(write_x_load_y);    std::thread b(write_y_load_x);    a.join();    b.join();    assert(!x_was_zero || !y_was_zero);}
  1. Given the constraints that everything can be atomic except access to x, how can I guarantee that the assert passes?
  2. If that's not possible as-is, is it possible if access to x can be atomic but no stronger than "relaxed"?
  3. What is the least amount of synchronization (e.g. weakest memory models for all operations) necessary to guarantee this?

It's my understanding that without any form of fences or atomic access, it's possible (if only theoretically so) for the store x = 1 to sink below the load y == 0 (having been moved by the CPU if not per se by the compiler), causing a potential race where both x and y are 0 (and triggering that assertion).

I was initially under the naïve impression that SEQ_CST guarantees total ordering of non-atomic variables. That is, a non-atomic (or relaxed) store of x ordered before a SEQ_CST load of y is guaranteed to actually happen first; similarly a SEQ_CST store of y ordered before a non-atomic (or relaxed) load of x is guaranteed to actually happen first; put together that would prevent the race. However, on further reading of https://en.cppreference.com/w/cpp/atomic/memory_order, I don't think the documentation actually says this, but rather that such ordering is only guaranteed for the opposite case (loads before stores), or cases where access to both x and y are SEQ_CST.

Similarly, I naïvely had thought that a memory barrier would force all loads OR stores before the barrier to happen before all loads OR stores after it, but reading https://en.cppreference.com/w/cpp/atomic/atomic_thread_fence seems to imply that it's again only true for forcing ordering of loads before the barrier with stores after it. That doesn't help here either, I think, unless I'm supposed to put barriers in a less obvious place than "between the store and the load".

What synchronization method should I use here? Is it even possible?


Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images