liveBook · Manning

Acquire-release semantics

As explained in Modern C, Third Edition

Release semantics are memory-ordering properties that make preceding effects available to a thread that synchronizes with the release operation.

An atomic value carries a visibility guarantee

Start with `_Atomic(unsigned) x = 11`. Suppose one thread executes `++x; x = 31;` and another executes `unsigned y = x;`. If that read obtains the 31 written by the first thread, it synchronizes with the write. Effects that happened before the write are then visible to evaluations after the read—not merely the new value of `x`. section 21.1

Release semantics belong to the writer side of a synchronization; acquire semantics belong to the reader side. An operation that reads and writes can have acquire-release semantics. The direction matters: a release does not, by itself, make another thread observe anything. section 21.1

TAKEAWAY: establish the synchronization before relying on visibility.

  • An acquire operation synchronizes with a release operation when it reads the value written by that release. section 21.1
  • When that synchronization occurs, effects before the release must be visible at evaluations after the acquire. section 21.1
  • A mutex provides another route: a newly acquired lock makes effects of previous critical sections protected by that mutex visible. section 21.2
Table 21.1 C library functions that form synchronization pairs
Release Acquire
thrd_create(.., f, x) Entry to f(x)
thrd_exit by thread id or return from f Start of tss_t destructors for id
End of tss_t destructors for id thrd_join(id) or atexit/at_quick_exit handlers
call_once(&obj, g), first call call_once(&obj, h), all subsequent calls
Mutex release Mutex acquisition

Synchronization is not confined to atomic expressions. The table pairs release and acquire events supplied by C library operations, including mutexes and thread lifecycle calls. section 21.2

Do not mistake a wake-up for visibility. A condition-variable wait releases its mutex before suspending and acquires it again on return; synchronization goes through the mutex, not the condition variable. Protect a signal and the associated non-atomic changes with the same mutex used by waiters. Explicit acquire-release consistency may cost less than the default sequential consistency of atomics, but choosing arguments for `_explicit` atomic functions requires a careful synchronization design. section 21.2 section 21.5

How Modern C, Third Edition covers it

How deep it goes
Defines directional operations and the read-from synchronization rule, then states its visibility consequence; defers relaxed atomic operations.
Examples
Uses two threads exchanging an atomic value and a table of C library release-acquire pairs.
What it assumes
Assumes familiarity with C threads and shared objects while defining synchronization through atomic reads and writes.
What you can do after
Evaluate/understand whether an atomic read or mutex acquisition makes another thread’s preceding effects visible.
How it connects
Connects happened-before, atomic read-modify-write operations, mutexes, condition variables, and sequential consistency.

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 Modern C, Third Edition. The section links point to the parts of the book it draws on.