CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
Atomics

C11-style atomic types and operations, with one consistent spelling across compilers and platforms.

Declaring an atomic

Wrap a type in atomic(type) to declare an atomic variable or struct field:

atomic(int32) counter;
atomic(ptr) head;
atomic(bool) done;

The available type tokens are: ptr (a void*), bool, size (size_t), intptr, uintptr, int8, int16, int32, int64, uint8, uint16, uint32, and uint64.

An atomic variable must not be read or written directly - always go through the operations below, which take the same type token used to declare it.

Memory orders

Every operation takes a memory order, written as a bare name (the operation macro adds the required prefix internally): Relaxed, Acquire, Release, AcqRel, or SeqCst. These match the C11 memory order semantics of the same names - Relaxed only guarantees atomicity of the operation itself, Acquire/Release establish a happens-before relationship between a store and a later load of the same value, AcqRel combines both for read-modify-write operations, and SeqCst adds a single total order across all SeqCst operations for cases that need the strongest guarantee.

Operations

atomic(int32) counter;
atomicStore(int32, &counter, 0, Relaxed);
int32 prev = atomicFetchAdd(int32, &counter, 1, AcqRel);
atomic(ptr) head;
void *cur = atomicLoad(ptr, &head, Acquire);
void *newnode = ...;
if (atomicCompareExchange(ptr, strong, &head, &cur, newnode, AcqRel, Acquire)) {
// cur was still the current value of head, and head is now newnode
} else {
// cur has been updated to head's actual current value; try again
}
Note
A true weak compare-exchange isn't available everywhere: some platforms implement weak the same as strong, so don't rely on being able to observe a spurious weak failure - only on the fact that a strong failure is never spurious.

64-bit atomics on 32-bit platforms

atomic(int64) and atomic(uint64) work on 32-bit platforms as well as 64-bit ones. On 32-bit x86 specifically, the read-modify-write operations (atomicExchange, atomicCompareExchange, and the atomicFetch* family) are implemented with a compare-and-swap retry loop rather than a single instruction, since the platform exposes no native 8-byte instruction for them. atomicLoad and atomicStore use a fast path where available. Expect 64-bit atomics to be slower than other sizes on 32-bit x86, and avoid them on hot paths that must also run there.