Atomic operations for lock-free concurrency

Marcus Chen Jan 2026
1 tab
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;

fn main() {
    let counter = Arc::new(AtomicUsize::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter_clone = Arc::clone(&counter);
        handles.push(thread::spawn(move || {
            counter_clone.fetch_add(1, Ordering::SeqCst);
        }));
    }

    for h in handles {
        h.join().unwrap();
    }
    println!("Count: {}", counter.load(Ordering::SeqCst));
}
1 file · rust Explain with highlit

For high-performance concurrent code, atomics provide lock-free synchronization. The std::sync::atomic module has AtomicBool, AtomicUsize, etc., with operations like load, store, fetch_add, and compare_exchange. These compile to CPU-level atomic instructions. I use atomics for counters, flags, and simple shared state where mutexes would be overkill. The Ordering parameter (Relaxed, Acquire, Release, SeqCst) controls memory ordering, which is subtle but critical for correctness. For most cases, SeqCst is safe but slower; Relaxed is faster but requires careful reasoning. Atomics are the foundation of lock-free data structures, but I only reach for them when profiling shows locks are a bottleneck.