_Atomic ( type-name ) | (1) | (since C11) |
_Atomic type-name | (2) | (since C11) |
type-name | - | any type other than array or function. For (1), type-name also cannot be atomic or cvr-qualified |
The header <stdatomic.h>
defines 37 convenience type aliases, from atomic_bool
to atomic_uintmax_t
, which simplify the use of this keyword with built-in and library types.
_Atomic const int * p1; // p is a pointer to an atomic const int const atomic_int * p2; // same const _Atomic(int) * p3; // same
If the macro constant __STDC_NO_ATOMICS__
is defined by the compiler, the keyword _Atomic
is not provided.
Objects of atomic types are the only objects that are free from data races; that is, they may be modified by two threads concurrently or modified by one and read by another.
Each atomic object has its own associated modification order, which is a total order of modifications made to that object. If, from some thread's point of view, modification A
of some atomic M happens-before modification B
of the same atomic M, then in the modification order of M, A occurs before B.
Note that although each atomic object has its own modification order, there is no single total order; different threads may observe modifications to different atomic objects in different orders.
There are four coherences that are guaranteed for all atomic operations:
Some atomic operations are also synchronization operations; they may have additional release semantics, acquire semantics, or sequentially-consistent semantics. See memory_order
.
Built-in increment and decrement operators and compound assignment are read-modify-write atomic operations with total sequentially consistent ordering (as if using memory_order_seq_cst
). If less strict synchronization semantics are desired, the standard library functions may be used instead.
Atomic properties are only meaningful for lvalue expressions. Lvalue-to-rvalue conversion (which models a memory read from an atomic location to a CPU register) strips atomicity along with other qualifiers.
Accessing a member of an atomic struct/union is undefined behavior.
The library type sig_atomic_t
does not provide inter-thread synchronization or memory ordering, only atomicity.
The volatile types do not provide inter-thread synchronization, memory ordering, or atomicity.
Implementations are recommended to ensure that the representation of _Atomic(T)
in C is same as that of std::atomic<T>
in C++ for every possible type T
. The mechanisms used to ensure atomicity and memory ordering should be compatible.
#include <stdio.h> #include <threads.h> #include <stdatomic.h> atomic_int acnt; int cnt; int f(void* thr_data) { for(int n = 0; n < 1000; ++n) { ++cnt; ++acnt; // for this example, relaxed memory order is sufficient, e.g. // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed); } return 0; } int main(void) { thrd_t thr[10]; for(int n = 0; n < 10; ++n) thrd_create(&thr[n], f, NULL); for(int n = 0; n < 10; ++n) thrd_join(thr[n], NULL); printf("The atomic counter is %u\n", acnt); printf("The non-atomic counter is %u\n", cnt); }
Possible output:
The atomic counter is 10000 The non-atomic counter is 8644
C++ documentation for atomic |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/atomic