Might be stupid but rather being asked than regret for the rest of my life.
The standard pattern of std::atomic::load and std::atomic::store would be
something like this
N.B.: assume that in all examples below the initial value for data is 0
writer:
data = 42;
sync_after_write.store(1, memory_order_release);
reader:
while (sync_after_write.load(memory_order_acquire) != 1) {}
assert(data == 42); // must hold
I'm wondering if there is a way to express the reversed pattern where sync happens before storing the data value. The idea is to ensure that the writer hasn't started modifying the data and the reader still has the original value of it.
Something along these lines
writer:
sync_before_write.store(1, /* which memory access ? */); // we want to prevent subsequent
// stores to appear before this statement
data = 42;
reader:
data_copy = data;
if (sync_before_write.load(/* which memory access ? */) == 0) { // we want to prevent previous
// loads to appear after this statement
assert(data_copy == 0); // in other words since sync_before_write is zero then
// the writer hasn't started modifying the data value
// yet and it stays to be zero (original)
}
Edit: I should admit it was not clear from the beginning, data is NOT atomic and may require multiple cycles to read/write from/to
You can only do this if both
dataandsyncarestd::atomicso you can useacquire/releaseon both. If you can't do that, you'll have to do something else.Detecting potential tearing in
dataafter already copying it is something C++ doesn't support, but is what the seqlock pattern does, and it is possible to hack that up in C++ in a way that compiles to working asm with real compilers for real ISAs.To simplify your problem, you have one thread with
... and another thread with
This requires only acquire/release ordering, due to two relationships:
sync = 1is sequenced beforedata = 42and thus happens before the otherdata = 42may synchronize withdata_copy = data.If
data = 42synchronizes withdata_copy = data, thensync = 1happens beforedata_copy = databecause the happens before relationship is acyclic.An intuitive model for acquire/release is that each acquiring thread sees a certain point on the timeline of other threads' release operations. It is not possible to see release operations in reversed order. If
sync == 0, thensync = 1has not yet happened anddata = 42has not yet happened either.Note: Perhaps you should use something like a
std::mutexif you can't make both atomic.