# Atomics
# atomics and operators
Atomic variables can be accessed concurrently between different threads without creating race conditions.
/* a global static variable that is visible by all threads */
static unsigned _Atomic active = ATOMIC_VAR_INIT(0);
int myThread(void* a) {
++active; // increment active race free
// do something
--active; // decrement active race free
return 0;
}
All lvalue operations (operations that modify the object) that are allowed for the base type are allowed and will not lead to race conditions between different threads that access them.
- Operations on atomic objects are generally orders of magnitude slower than normal arithmetic operations. This also includes simple load or store operations. So you should only use them for critical tasks.
- Usual arithmetic operations and assignment such as
a = a+1;
are in fact three operations ona
: first a load, then addition and finally a store. This is not race free. Only the operationa += 1;
anda++;
are.
# Syntax
#ifdef __STDC_NO_ATOMICS__
# error this implementation needs atomics
#endif
#include <stdatomic.h>
- unsigned _Atomic counter = ATOMIC_VAR_INIT(0);
# Remarks
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.
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.