Course contentsShow
← Rust
Lesson 1060 of 1,9109. Smart Pointers and Interior MutabilityFree lesson

Shared State in Service Architectures

Manage global application state using atomic smart pointers.

In this lesson, you will learn how to manage globally accessible application state across concurrent threads using atomic smart pointers.

The Challenge of Global State

In service architectures—such as web servers or concurrent task runners—multiple threads often need to read and update shared data simultaneously. Because Rust enforces strict ownership rules, you cannot simply pass a mutable reference to a global variable across thread boundaries. Instead, we use a combination of Arc (Atomic Reference Counting) and Mutex (or RwLock) to ensure memory safety while providing shared access.

Orchestrating Shared State

When you need to share state, Arc provides the "shared" aspect: it allows multiple owners to keep the data alive as long as at least one reference exists. However, Arc only grants immutable access. To modify that data safely, you wrap your state inside a Mutex or RwLock.

Consider a simple shared counter for a service:

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    // Wrap the data in Mutex for interior mutability, 
    // then Arc to share it across threads.
    let counter = Arc::new(Mutex::new(0));

    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }

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

    println!("Final count: {}", *counter.lock().unwrap());
}

Why This Pattern Works

The Arc pointer handles the reference counting in an atomic way, ensuring that the memory isn't dropped prematurely as threads finish their tasks. The Mutex provides the "interior mutability" required to transition from the shared, immutable Arc reference to a mutable state. By calling .lock(), we obtain a guard that grants us temporary, safe access to the underlying data, adhering to Rust’s core guarantee that data is either shared or mutated, but never both at the same time in an uncontrolled fashion.

Key Takeaway: Use Arc<Mutex<T>> to distribute mutable ownership of service state across threads, relying on atomic counting for memory management and mutexes for synchronous interior mutability.