3
votes

The GCC Wiki says this about the memory model synchronization mode Acquire/Release:

To make matters a bit more complex, the interactions of non-atomic variables are still the same. Any store before an atomic operation must be seen in other threads that synchronize. For example:

 -Thread 1-
 y = 20;
 x.store (10, memory_order_release);

 -Thread 2-
 if (x.load(memory_order_acquire) == 10)
    assert (y == 20);
Since 'y' is not an atomic variable, the store to 'y' happens-before the store to 'x', so the assert cannot fail in this case. The optimizers must still limit the operations performed on shared memory variables around atomic operations.

Now, what if I make 'y' an atomic variable (without imposing happens-before restrictions)?

 -Thread 1-
 y.store (20, memory_order_relaxed);
 x.store (10, memory_order_release);

 -Thread 2-
 if (x.load(memory_order_acquire) == 10)
    assert (y.load (memory_order_relaxed) == 20);

Can the assert fail? Are there fewer requirements for atomic variables than for non-atomic variables? Or is the Wiki's restriction to non-atomic variables gratuitous and misleading here?

1
Anything guaranteed for regular memory operations is also guaranteed for relaxed atomic operations.curiousguy

1 Answers

4
votes

Since 'y' is not an atomic variable, the store to 'y' happens-before the store to 'x'

The statement "since y is not an atomic" is incorrect.. The same ordering rules apply to atomic and non-atomic operations.

Acquire/release barriers guarantee that memory operation A (the store to y) sequenced before the store/release happens-before memory operation B (the assert) sequenced after the load/acquire that sees the stored value. Whether or not operations A and B are atomic is irrelevant.
The assert cannot fire.