liveBook · Manning

Acquire-release semantics

As explained in C++ Concurrency in Action, Second Edition

Acquire-release ordering provides synchronization when an acquire operation reads a value written by a release operation, without imposing a single global order.

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

How C++ Concurrency in Action, Second Edition covers it

How deep it goes
Works through matching release and acquire operations, their ordering of relaxed writes, transitive synchronization, and the absence of total order.
Examples
Uses two atomic flags, a release-published relaxed write, and a three-thread synchronization chain.
What it assumes
Assumes basic familiarity with C++ threads and atomic loads and stores.
What you can do after
Apply it via std::atomic release stores and acquire loads to publish earlier writes between threads.
How it connects
Relates acquire-release ordering to happens-before, relaxed ordering, sequential consistency, and atomic operations.

Also explained in

Compare how 4 books explain acquire-release semantics →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of C++ Concurrency in Action, Second Edition. The section links point to the parts of the book it draws on.