15. Atomics and volatile
15.1 Atomic types#
var ready: @bool
var hits: @u64
var head: @Node*?
hits += 1 # checked atomic add: traps on overflow
hits +%= 1 # C11 fetch-add, wrapping
ready = true # store, seq_cst
if ready: ... # load, seq_cst
let previous = hits.fetch_add(1, order = .relaxed)
ready.store(true, order = .release)
while not ready.load(order = .acquire): ...
match head.compare_exchange(expected = old, desired = new, success = .acq_rel, failure = .acquire):
.none: ... # exchanged
.some(observed): ... # not exchanged; observed is the current value
atomic.fence(.release)
- Plain reads and
=are sequentially consistent loads and stores. +=and-=are sequentially consistent read-modify-write operations that trap on overflow, implemented as a compare-exchange loop, so the overflow rule holds for atomics too.+%=and-%=are C11's wrappingfetch_addandfetch_sub.|=,&=,^=arefetch_or,fetch_and,fetch_xor.- The methods
load,store,swap,fetch_add,fetch_sub,fetch_or,fetch_and,fetch_xor(all wrapping) take anOrdering:relaxed,acquire,release,acq_rel,seq_cst.compare_exchange(expected, desired, success, failure) -> T?answersnonewhen it exchanged and the observed value when it did not, which is C11's write-back ofexpectedas a value;failuremay not bereleaseoracq_reland may not be stronger thansuccess.compare_exchange_weakmay fail spuriously.atomic.fence(order)is a standalone fence. - Every
@Tis lock-free by construction. There is no atomic struct. - Semantics are the C11 memory model.
Why on the type. Atomicity is a property of the location. If the marker were on the access, forgetting it once would be a plain access to the same location, which is a data race by definition; with it on the type, every access is atomic and the compiler can prove no mixed access exists. Refusing atomic structs refuses the lock C11 hides behind _Atomic struct.
15.2 volatile#
A load or store through volatile T* is an observable effect: never elided, merged, reordered with another volatile access or an asm block, or widened. It says nothing about other threads. Hardware registers use volatile; shared memory uses @.