Course contentsShow
← Rust
Lesson 970 of 1,9108. Collections and Iterator PipelinesFree lesson

Lock-Free Concurrent Collections

You will be able to build high-concurrency maps that avoid traditional mutex overhead.

In this lesson, you will learn how to design high-concurrency maps that leverage atomic primitives to bypass the performance bottlenecks of traditional mutexes.

The Problem with Mutexes

When you use a standard Mutex<HashMap<K, V>>, you introduce a global synchronization point. Even if two threads are updating completely different keys, one must wait for the other to release the lock. In high-throughput pipelines—like the ones we’ve built using Rayon—this "data contention" turns your multi-threaded application into a serial one.

The Lock-Free Strategy: Compare-And-Swap (CAS)

Lock-free collections avoid blocking by relying on hardware-level atomic operations, specifically Compare-And-Swap (CAS). Instead of locking a bucket, a thread attempts to update a pointer to a data node. If the thread detects that the pointer has changed since it last checked, it simply retries the operation.

Imagine an array of atomic pointers representing buckets in a hash map. To insert a key, you don't lock the array; you perform a CAS loop:

use std::sync::atomic::{AtomicPtr, Ordering};

// A simplified look at a concurrent bucket
struct Node<K, V> {
    key: K,
    value: V,
    next: AtomicPtr<Node<K, V>>,
}

// Thread-safe update without a Mutex
fn insert(head: &AtomicPtr<Node<K, V>>, new_node: *mut Node<K, V>) {
    loop {
        let current = head.load(Ordering::Acquire);
        unsafe { (*new_node).next.store(current, Ordering::Relaxed); }
        
        if head.compare_exchange(current, new_node, Ordering::Release, Ordering::Relaxed).is_ok() {
            break;
        }
    }
}

Why this scales

Because there is no "lock" held, other threads are never suspended by the OS scheduler. Even if a thread fails its CAS attempt, it is immediately ready to retry based on the new, updated state of the collection. This pattern is particularly powerful when combined with the iterator pipelines we’ve studied; you can partition your data processing across cores, and each core can "push" results into a shared, lock-free structure without stalling the entire pipeline.

While implementing these structures from scratch requires careful attention to memory ordering, the core principle is simple: use atomic state transitions to ensure progress, rather than blocking threads with mutual exclusion.

Key Takeaway: Lock-free collections trade the simplicity of Mutexes for higher throughput by using atomic Compare-And-Swap loops to resolve data contention without ever suspending execution threads.