atomic
import std::sync::atomic; · source
Atomic<T>
type struct Atomic<T> {
value: T;
static new(initial: T) -> Atomic<T>;
load(&this, order: MemoryOrder) -> T;
store(mut &this, val: T, order: MemoryOrder) -> void;
fetch_add(mut &this, val: T, order: MemoryOrder) -> T;
fetch_sub(mut &this, val: T, order: MemoryOrder) -> T;
fetch_and(mut &this, val: T, order: MemoryOrder) -> T;
fetch_or(mut &this, val: T, order: MemoryOrder) -> T;
fetch_xor(mut &this, val: T, order: MemoryOrder) -> T;
swap(mut &this, val: T, order: MemoryOrder) -> T;
compare_exchange(mut &this, current: T, next: T, succ: MemoryOrder, fail: MemoryOrder) -> Result<T, T>;
}
One generic cell driven by the compiler's atomic intrinsics, which lower directly to LLVM's atomicrmw, cmpxchg, and atomic load/store. No libc, no spin loops, no calls.
import std::sync::atomic;
mut hits: Atomic<u64> = Atomic<u64>::new(0);
hits.fetch_add(1, MemoryOrder::Relaxed);
const total: u64 = hits.load(MemoryOrder::SeqCst);
T is dispatched at compile time with static match (T), so Atomic<u32>::load lowers to exactly the u32 atomic and nothing else. LLVM does not distinguish signed from unsigned for atomic integer memory operations, so the i32, i64, and boolean arms bitcast onto the same unsigned intrinsics.
Supported types are u8, u32, u64, i32, i64, and boolean. Instantiating Atomic<T> with anything else — or calling fetch_add on Atomic<boolean> — is a compile error (E0645). The absence of a matching static match arm is the type constraint; no trait bound is needed.
| Method | Returns |
|---|---|
load(order) / store(val, order) | T / void |
fetch_add / fetch_sub / fetch_and / fetch_or / fetch_xor | T — the previous value. |
swap(val, order) | T — the previous value. |
compare_exchange(current, next, succ, fail) | Ok(prev) on swap, Err(actual) on mismatch. |
Atomic cells are deliberately not
Copy. Mutation through a shared pointer has to stay explicit, and bitwise-copying an atomic would silently break that. Wrap inArc<Atomic<T>>to share.
Trait implementations
implement trait Drop for struct Atomic<T>
A no-op; it exists so Atomic<T> satisfies T: Drop bounds inside containers.
MemoryOrder
type enum MemoryOrder : u32 {
Relaxed = 2;
Acquire = 4;
Release = 5;
AcqRel = 6;
SeqCst = 7;
}
implement enum MemoryOrder {
static to_u32(order: MemoryOrder) -> u32;
}
| Order | Meaning |
|---|---|
Relaxed | Atomicity only, no ordering. Cheapest; correct for hit counters where the sequence of observed values doesn't matter. |
Acquire | On loads and RMW: no later access moves above this one. Pairs with Release. |
Release | On stores and RMW: no earlier access moves below this one. Pairs with Acquire. |
AcqRel | Both, for RMW operations only. |
SeqCst | Full sequential consistency — every thread observes the same global order. |
When in doubt, SeqCst is always safe. A load cannot use Release. The numeric values are LLVM's ordering codes, which is why the enum starts at 2; the name avoids clashing with core::cmp::Ordering.
Fences
function fence(order: MemoryOrder) -> void;
function compiler_fence(order: MemoryOrder) -> void;
fence(order) emits a real LLVM fence. Because a Relaxed fence would be meaningless, a weaker request is clamped up to SeqCst rather than producing invalid IR. compiler_fence(order) is for constraining the compiler's reordering rather than the CPU's — signal handlers, longjmp paths — though today it conservatively lowers to a real fence too.