#ifdef __STDC_NO_ATOMICS__
# error this implementation needs atomics
#endif
#include <stdatomic.h>
Atomics as part of the C language are an optional feature that is available since C11.
Their purpose is to ensure race-free access to variables that are shared between different threads. Without atomic qualification, the state of a shared variable would be undefined if two threads access it concurrently. Eg an increment operation (++
) could be split into several assembler instructions, a read, the addition itself and a store instruction. If another thread would be doing the same operation their two instruction sequences could be intertwined and lead to an inconsistent result.
Types: All object types with the exception of array types can be qualified with _Atomic
.
Operators: All read-modify-write operators (e.g ++
or *=
) on these are guaranteed to be atomic.
Operations: There are some other operations that are specified as type generic functions, e.g atomic_compare_exchange
.
Threads: Access to them is guaranteed not to produce data race when they are accessed by different threads.
Signal handlers: Atomic types are called lock-free if all operations on them are stateless. In that case they can also be used to deal state changes between normal control flow and a signal handler.
There is only one data type that is guaranteed to be lock-free: atomic_flag
. This is a minimal type who's operations are intended to map to efficient test-and-set hardware instructions.
Other means to avoid race conditions are available in C11's thread interface, in particular a mutex type mtx_t
to mutually exclude threads from accessing critical data or critical sections of code. If atomics are not available, these must be used to prevent races.