Expand description
§Thread Safety Primitives
Based on “Formal methods for the unsafe side of the Force” (Antithesis, 2026). Provides rigorously defined primitives for bridging FFI and multi-threaded boundaries.
§RelaxedAtomic<T>
Provides inner mutability for Copy types via relaxed atomic loads and stores.
On x86_64 and ARM, relaxed loads/stores compile to the same instructions as
regular memory accesses (no LOCK prefix), making this a zero-overhead way to
achieve interior mutability for atomic-compatible types.
For u32, provides fetch_add and fetch_sub methods that use atomic
read-modify-write operations. These are atomic but emit LOCK-prefixed
instructions on x86_64 (though without the stronger ordering fence overhead
of SeqCst).
For simple load-mutate-store patterns, use the load–store methods:
let counter = RelaxedAtomic::new(0u32);
let val = counter.load();
counter.store(val + 1);For atomic increments/decrements, use fetch_add/fetch_sub:
let counter = RelaxedAtomic::new(0u32);
counter.fetch_add(1); // Atomic, no race condition§WARNING: Race Conditions Are Still Possible
Rust prevents data races, not race conditions. (See “Rust Prevents Data Races, Not Race Conditions” by Matthias Endler.)
A data race is unsynchronized concurrent access where at least one side writes. This is Undefined Behavior and Rust’s type system prevents it.
A race condition is any bug where the result depends on timing or thread interleaving. Rust does not prevent these.
The load–mutate–store pattern is not atomic as a whole:
// DANGEROUS: Two threads can interleave between load and store
let val = counter.load();
// <--- Another thread could load and store here
counter.store(val + 1);This is the classic TOCTOU (Time-of-Check-Time-of-Use) bug. See the bank account example in the article above.
§When to use
Use when a field needs interior mutability and is accessed without
contention (same pattern as the original C code using plain loads/stores).
If you need multi-step atomic operations (CAS, fetch_add), use the
underlying std::sync::atomic types directly.
§When not to use
Do not use when the operation must be atomic relative to other threads. The load–mutate–store pattern is not atomic as a whole — it can race with concurrent stores. Use only where the C code would have used a non-atomic access that happens to be race-free by design.
§Correct usage examples
// CORRECT: Single-threaded or single-writer scenario
let flag = RelaxedAtomic::new(false);
// Only one thread ever writes to this
flag.store(true);
// CORRECT: Using fetch_add for atomic increment
let counter = RelaxedAtomic::new(0u32);
counter.fetch_add(1); // Atomic, no race condition
// CORRECT: Read-only scenario
let config = RelaxedAtomic::new(42u32);
let val = config.load(); // Multiple readers, no writers§Incorrect usage examples
// INCORRECT: Non-atomic compound operation
let counter = RelaxedAtomic::new(0u32);
// Two threads doing this simultaneously can lose updates
let val = counter.load();
counter.store(val + 1);
// INCORRECT: Check-then-act (TOCTOU)
let balance = RelaxedAtomic::new(100u32);
// Thread A: check balance
let can_withdraw = balance.load() >= 100;
// <--- Thread B could withdraw here
// Thread A: withdraw
if can_withdraw {
balance.store(balance.load() - 100);
}Structs§
- Main
Thread Token - A witness of execution that exists solely on a designated “Main Thread”.
- Relaxed
Atomic - Provides inner mutability for
Copytypes via relaxed atomic operations. - Send
Wrapper - A wrapper that allows sending non-
Sendtypes across thread boundaries.
Traits§
- Atomic
Repr - Trait for types that can be stored in a
RelaxedAtomic.
Functions§
- designate_
main_ thread - Designate the calling thread as the application’s main thread.
- main_
thread_ id - Returns the
ThreadIdpreviously designated as the main thread, if any.