Course contentsShow
← Rust
Lesson 1104 of 1,91010. Concurrency PrimitivesFree lesson

Thread-Local Storage Patterns

You will maintain thread-specific global state to avoid contention on shared resources.

In this lesson, you will learn how to bypass global contention by giving every thread its own private "sandbox" of data using Thread-Local Storage (TLS).

The Problem: Global Contention

When multiple threads share a single Mutex or Atomic variable, they inevitably fight for access. Even with efficient primitives, frequent lock acquisition causes "contention," where threads are forced to wait in line. If the data you are accessing doesn't strictly need to be shared across threads—such as a logger, a temporary buffer, or a random number generator—you are paying a performance penalty for no reason.

The Solution: Thread-Local Storage

Thread-Local Storage allows you to declare a static variable that has a unique instance for every thread that accesses it. When a thread accesses a thread-local variable, it gets its own private copy. Since no other thread can touch that specific instance, you don't need locks, mutexes, or atomic synchronization to modify it.

In Rust, we use the thread_local! macro to define these variables.

use std::cell::RefCell;

thread_local! {
    static COUNTER: RefCell<u32> = RefCell::new(0);
}

fn increment() {
    COUNTER.with(|cell| {
        *cell.borrow_mut() += 1;
    });
}

In this example, every thread that calls increment() maintains its own independent COUNTER. Thread A’s increments will never affect Thread B’s. Because the data is local to the thread, we don't need to worry about memory ordering or deadlocks; the runtime handles the initialization and storage management behind the scenes.

When to use this pattern

You should reach for TLS when you notice high contention on a global resource that is being used as a "scratchpad." It is common in high-performance applications for caching, tracking thread-specific statistics, or managing complex state like database connection handles that should not be shared across thread boundaries to maintain data integrity.

Key Takeaway: Thread-Local Storage eliminates contention and synchronization overhead by ensuring each thread manages its own isolated instance of a global variable.