Skip to content
CryoCryo home
Stdlibsync

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.

MethodReturns
load(order) / store(val, order)T / void
fetch_add / fetch_sub / fetch_and / fetch_or / fetch_xorT — 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 in Arc<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;
}
OrderMeaning
RelaxedAtomicity only, no ordering. Cheapest; correct for hit counters where the sequence of observed values doesn't matter.
AcquireOn loads and RMW: no later access moves above this one. Pairs with Release.
ReleaseOn stores and RMW: no earlier access moves below this one. Pairs with Acquire.
AcqRelBoth, for RMW operations only.
SeqCstFull 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.