A write that another thread can see
An input thread changes data, then writes an atomic object. An account thread reads the value written by the input thread. That read synchronizes with the write: the earlier changes are now visible to the account thread. The direction matters—the write is the releasing side, and the read is the acquiring side. section 19.1
A release operation publishes effects that happened before it. An acquire operation that reads the value written by that release synchronizes with it. TAKEAWAY: if a release synchronizes with an acquire, effects before the release are visible at evaluations after the acquire. An atomic read-modify-write operation can have both acquire and release semantics. section 19.1
C provides these properties through both atomic operations and paired library calls:
- Use memory_order_release for a release-only operation, typically atomic_store or atomic_flag_clear; use memory_order_acquire for an acquire-only operation, typically atomic_load. section 19.4
- Use memory_order_acq_rel when an atomic operation both reads and writes, as with atomic_fetch_add, atomic_compare_exchange_weak, or atomic_flag_test_and_set. section 19.4
- Use matching library synchronization, such as the first successful call_once initialization and subsequent calls with the same object, or mutex release and acquisition. section 19.2
Selecting a memory order
atomic_fetch_add_explicit(&at, 1, memory_order_acq_rel) requests acquire-release consistency for one read-modify-write operation. The _explicit interface selects a memory order; the corresponding interface without _explicit uses sequential consistency. A store-only operation cannot request acquire semantics, because it has no acquiring side. section 19.4
Table 19.1. C library functions that form synchronization pairs (view table figure)
| 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 |
The table pairs releasing and acquiring C library events, including thread creation and joining, call_once, and mutex operations. section 19.2
TAKEAWAY: acquire-release consistency can avoid the additional total ordering required by sequential consistency, but choosing explicit orders requires care. A relaxed atomic operation remains indivisible but adds no synchronization requirement; it cannot substitute for a release-acquire pair that must make earlier effects visible. section 19.4 section 19.5



