Smart Pointers

Mutex<T>

std::sync::Mutex<T> (Mutual Exclusion) is a thread-safe interior mutability container that protects shared data by allowing at most one thread to access the inner value T at any given time. Unlike C or Java where a mutex is a standalone lock object separate from the data it protects, a Rust Mutex<T> owns T directly inside the lock, making it impossible to access T without first acquiring the lock.

Acquiring a Lock and MutexGuard<'_, T>

Calling .lock() blocks the current thread until the mutex is available and returns a LockResult<MutexGuard<'_, T>>. The returned MutexGuard<'_, T> is an RAII smart pointer that:

  • Implements Deref<Target = T> and DerefMut<Target = T> so you can read and mutate the protected data through *guard or method calls.
  • Automatically unlocks the mutex in its Drop implementation when the guard leaves scope (even during a panic unwind).
Mutex<T> Access Flow:

Thread A calls mutex.lock() ---> Acquires OS/futex lock
                                        |
                                        v
                            Returns MutexGuard<'_, T>
                            (Deref & DerefMut to T)
                                        |
                                        v
                        Guard goes out of scope (Drop) ---> Automatically unlocks
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let balance = Arc::new(Mutex::new(100_i64));

    thread::scope(|s| {
        for delta in [50_i64, -30, 80] {
            let balance = Arc::clone(&balance);
            s.spawn(move || {
                let mut guard = balance.lock().unwrap();
                *guard += delta;
            }); // `guard` drops here, releasing the lock immediately.
        }
    });

    println!("final balance: {}", *balance.lock().unwrap());
}
final balance: 200

Core Mutex<T> Methods

Method Signature Behavior
Mutex::new(val) const fn new(t: T) -> Mutex<T> Creates an unlocked mutex holding t (const-constructible, usable in static)
.lock() fn lock(&self) -> LockResult<MutexGuard<'_, T>> Blocks current thread until lock is acquired
.try_lock() fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> Attempts to acquire lock immediately without blocking; returns Err(TryLockError::WouldBlock) if held
.into_inner() fn into_inner(self) -> LockResult<T> Consumes the Mutex and moves out T without locking
.get_mut() fn get_mut(&mut self) -> LockResult<&mut T> Returns &mut T with zero locking overhead when caller holds exclusive &mut Mutex<T>
.clear_poison() fn clear_poison(&self) Clears the poisoned flag after inspecting/repairing the inner state

Lock Poisoning

If a thread panics while holding a MutexGuard<'_, T>, the guard's destructor still unlocks the mutex so other threads do not deadlock, but it marks the Mutex<T> as poisoned because the panicking thread may have left T in a partially updated state. Subsequent calls to .lock() return Err(PoisonError<MutexGuard<'_, T>>).

Callers can either:

  1. Propagate the panic with .lock().unwrap().
  2. Recover the guard with .lock().unwrap_or_else(|poisoned| poisoned.into_inner()) after restoring invariants.
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let shared = Arc::new(Mutex::new(vec![1, 2]));

    let shared_clone = Arc::clone(&shared);
    let _ = thread::spawn(move || {
        let mut guard = shared_clone.lock().unwrap();
        guard.push(3);
        panic!("simulated failure mid-update");
    })
    .join();

    println!("is_poisoned: {}", shared.is_poisoned());

    // Recover the underlying guard despite poisoning:
    let guard = shared
        .lock()
        .unwrap_or_else(|poisoned| poisoned.into_inner());
    println!("recovered data: {:?}", *guard);
}
is_poisoned: true
recovered data: [1, 2, 3]

Avoiding Deadlocks by Dropping Guards Early

A Mutex<T> is not re-entrant: calling .lock() a second time on the same thread while an earlier MutexGuard is still alive deadlocks the thread. Calling drop(guard) explicitly (or using an inner block { ... }) before performing I/O or acquiring another lock minimizes lock contention and prevents self-deadlock.