Acquire-release ordering synchronizes threads through an atomic operation. A release store makes earlier writes visible to a thread whose acquire load reads that store. It does not impose one total order on all threads’ operations. section 5.3.3
Two flags, no total order
Two threads release-store to separate flags. Two others each acquire-load one flag, then check the other. Both checks can miss the other flag’s write: synchronization through one flag does not establish an order between the independent stores. section 5.3.3
Listing 5.8. Acquire-release operations can impose ordering on relaxed operations
#include <atomic>
#include <thread>
#include <assert.h>
std::atomic<bool> x,y;
std::atomic<int> z;
void write_x_then_y()
{
x.store(true,std::memory_order_relaxed); #1
y.store(true,std::memory_order_release); #2
}
void read_y_then_x()
{
while(!y.load(std::memory_order_acquire)); #3
if(x.load(std::memory_order_relaxed)) #4
++z;
}
int main()
{
x=false;
y=false;
z=0;
std::thread a(write_x_then_y);
std::thread b(read_y_then_x);
a.join();
b.join();
assert(z.load()!=0); #5
}
The writer relaxed-stores to x before release-storing to y. Once the reader’s acquire load sees y, its later relaxed load of x sees the earlier write. The release–acquire pair orders operations that are themselves relaxed. section 5.3.3
Synchronization can also pass through an intermediate thread: acquire a released flag, then release another. A third thread acquiring the second flag can observe writes made before the first release. section 5.3.3



