Course contentsShow
← Rust
Lesson 67 of 1,9101. Rust Fundamentals and ToolingFree lesson

Atomic Operations

Implement lock-free primitives to coordinate synchronization between multiple threads.

In this lesson, you will learn how to coordinate thread synchronization without traditional locks using atomic primitives.

The Problem with Shared State

When multiple threads access the same piece of data, we usually use a Mutex to ensure only one thread modifies it at a time. However, a Mutex forces threads to "wait in line," which can become a performance bottleneck.

What are Atomics?

Atomic operations are CPU-level instructions that allow you to read, modify, and write a value as a single, uninterrupted step. Because the CPU guarantees this happens "all at once," other threads can never see the data in a half-finished state. This allows us to build lock-free structures where threads communicate through shared memory without ever being put to sleep by the operating system.

A Simple Counter Example

Instead of wrapping an integer in a Mutex, we can use std::sync::atomic::AtomicUsize. Here is how you might increment a counter shared across threads:

use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;

fn main() {
    // Atomic types are thread-safe and can be shared across threads
    let counter = Arc::new(AtomicUsize::new(0));

    let mut handles = vec![];
    for _ in 0..10 {
        let c = Arc::clone(&counter);
        handles.push(thread::spawn(move || {
            // fetch_add increments the value atomically
            c.fetch_add(1, Ordering::SeqCst);
        }));
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Count: {}", counter.load(Ordering::SeqCst));
}

The Role of "Ordering"

You might notice the Ordering::SeqCst parameter. This tells the CPU how strictly it must organize memory operations around the atomic variable. SeqCst (Sequentially Consistent) is the safest and most intuitive mode—it ensures that all threads see all operations in the same order. While other orderings exist for performance optimization, we use SeqCst until we have a specific reason to do otherwise.

By using atomics, we achieve thread safety while remaining "lock-free," avoiding the overhead of operating system context switching.

Key Takeaway: Atomic operations provide a low-level way to perform thread-safe memory updates in a single, uninterrupted CPU step, enabling high-performance synchronization without the overhead of locks.