31. Atomics <stdatomic.h>
#
31.1. Introduction#
The header <stdatomic.h>
defines several macros and declares several types
and functions for performing atomic operations on data shared between
threads. [1]
Implementations that define the macro __STDC_NO_ATOMICS__
need not provide this header nor support any of its facilities.
The macros defined are the atomic lock-free macros
ATOMIC_BOOL_LOCK_FREE
ATOMIC_CHAR_LOCK_FREE
ATOMIC_CHAR16_T_LOCK_FREE
ATOMIC_CHAR32_T_LOCK_FREE
ATOMIC_WCHAR_T_LOCK_FREE
ATOMIC_SHORT_LOCK_FREE
ATOMIC_INT_LOCK_FREE
ATOMIC_LONG_LOCK_FREE
ATOMIC_LLONG_LOCK_FREE
ATOMIC_POINTER_LOCK_FREE
which indicate the lock-free property of the corresponding atomic types (both signed and unsigned); and
ATOMIC_FLAG_INIT
which expands to an initializer for an object of type atomic_flag
.
The types include
memory_order
which is an enumerated type whose enumerators identify memory ordering constraints;
atomic_flag
which is a structure type representing a lock-free, primitive atomic flag; and several atomic analogs of integer types.
In the following synopses:
An A refers to one of the atomic types.
A C refers to its corresponding non-atomic type.
An M refers to the type of the other argument for arithmetic operations. For atomic integer types, M is C. For atomic pointer types, M is
ptrdiff_t
.The functions not ending in
_explicit
have the same semantics as the corresponding_explicit
function withmemory_order_seq_cst
for thememory_order
argument.
NOTE Many operations are volatile-qualified. The “volatile as device register” semantics have not changed in the standard. This qualification means that volatility is preserved when applying these operations to volatile objects.
31.2. Initialization#
31.2.1. The ATOMIC_VAR_INIT
macro#
Synopsis
#include <stdatomic.h>
#define ATOMIC_VAR_INIT(C value)
Description
The ATOMIC_VAR_INIT macro expands to a token sequence suitable for initializing an atomic object of a type that is initialization-compatible with value. An atomic object with automatic storage duration that is not explicitly initialized using ATOMIC_VAR_INIT is initially in an indeterminate state; however, the default (zero) initialization for objects with static or thread-local storage duration is guaranteed to produce a valid state.
Concurrent access to the variable being initialized, even via an atomic operation, constitutes a data race.
EXAMPLE
atomic_int guide = ATOMIC_VAR_INIT(42);
31.2.2. The atomic_init generic function#
Synopsis
#include <stdatomic.h>
void atomic_init(volatile A *obj, C value);
Description
The atomic_init
generic function initializes the atomic object pointed to
by obj to the value value, while also initializing any additional state that
the implementation might need to carry for the atomic object.
Although this function initializes an atomic object, it does not avoid data races; concurrent access to the variable being initialized, even via an atomic operation, constitutes a data race.
Returns
The atomic_init generic function returns no value.
EXAMPLE
atomic_int guide;
atomic_init(&guide, 42);
31.3. Order and consistency#
The enumerated type memory_order
specifies the detailed regular
(non-atomic) memory synchronization operations as defined in (iso.5.1.2.4 and
may provide for operation ordering. Its enumeration constants are as follows:
[1]
memory_order_relaxed
memory_order_consume
memory_order_acquire
memory_order_release
memory_order_acq_rel
memory_order_seq_cst
For memory_order_relaxed
, no operation orders memory.
For memory_order_release, memory_order_acq_rel
and
memory_order_seq_cst
, a store operation performs a release operation on the
affected memory location.
For memory_order_acquire, memory_order_acq_rel
and
memory_order_seq_cst
, a load operation performs an acquire operation on the
affected memory location.
For memory_order_consume
, a load operation performs a consume operation on
the affected memory location.
There shall be a single total order S
on all memory_order_seq_cst
operations, consistent with the “happens before” order and modification orders
for all affected locations, such that each memory_order_seq_cst
operation
B that loads a value from an atomic object M observes one of the following
values:
the result of the last modification A of M that precedes B in S, if it exists, or
if A exists, the result of some modification of M in the visible sequence of side effects with respect to B that is not
memory_order_seq_cst
and that does not happen before A, orif A does not exist, the result of some modification of M in the visible sequence of side effects with respect to B that is not
memory_order_seq_cst
.NOTE 1
Although it is not explicitly required that S include lock operations, it can always be extended to an order that does include lock and unlock operations, since the ordering between those is already included in the “happens before” ordering.
NOTE 2
Atomic operations specifying
memory_order_relaxed
are relaxed only with respect to memory ordering. Implementations must still guarantee that any given atomic access to a particular atomic object be indivisible with respect to all other atomic accesses to that object.
For an atomic operation B that reads the value of an atomic object M, if
there is a memory_order_seq_cst
fence X sequenced before B, then B
observes either the last memory_order_seq_cst
modification of M preceding
X in the total order S or a later modification of M in its modification
order.
For atomic operations A and B on an atomic object M, where A modifies
M and B takes its value, if there is a memory_order_seq_cst
fence X
such that A is sequenced before X and B follows X in S, then B
observes either the effects of A or a later modification of M in its
modification order.
For atomic operations A and B on an atomic object M, where A modifies M and B takes its value, if there are memory_order_seq_cst fences X and Y such that A is sequenced before X, Y is sequenced before B, and X precedes Y in S, then B observes either the effects of A or a later modification of M in its modification order.
Atomic read-modify-write operations shall always read the last value (in the modification order) stored before the write associated with the read-modify-write operation.
An atomic store shall only store a value that has been computed from constants and program input values by a finite sequence of program evaluations, such that each evaluation observes the values of variables as computed by the last prior assignment in the sequence.[86] The ordering of evaluations in this sequence shall be such that
If an evaluation B observes a value computed by A in a different thread, then B does not happen before A. If an evaluation A is included in the sequence, then all evaluations that assign to the same variable and happen before A are also included.