Rust Tutorial · Smart Pointers and Concurrency · Lesson 25 of 29

Rust Shared State: Arc and Mutex

Share data between threads safely with Arc and Mutex, and how Send and Sync prevent data races at compile time.

Create a free account to save this page, take notes and track your progress. Sign in

Arc<Mutex<T>>

Arc (atomically reference counted) shares ownership across threads; Mutex lets one thread at a time change the data. Locking returns a guard that unlocks automatically when it goes out of scope.

Arc, Mutex and an atomic counter
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicU64, Ordering};
use std::thread;

fn main() {
    let inventory = Arc::new(Mutex::new(vec![10, 10, 10]));
    let requests = Arc::new(AtomicU64::new(0));
    let mut handles = Vec::new();
    for slot in 0..3 {
        let inventory = Arc::clone(&inventory);
        let requests = Arc::clone(&requests);
        handles.push(thread::spawn(move || {
            for _ in 0..4 {
                let mut stock = inventory.lock().unwrap();   // guard unlocks at end of scope
                stock[slot] -= 1;
                requests.fetch_add(1, Ordering::Relaxed);
            }
        }));
    }
    for h in handles { h.join().unwrap(); }
    println!("stock: {:?}, requests: {}", inventory.lock().unwrap(), requests.load(Ordering::Relaxed));
}

Output

stock: [6, 6, 6], requests: 12

Run this on your computer — see “Get Started” for setup.

Send and Sync

The compiler knows which types are safe to move (Send) or share (Sync) between threads. Trying to share an Rc or a RefCell across threads is a compile error, so data races can't happen in safe Rust.

For many readers and few writers use RwLock; for simple counters, atomics (AtomicU64).

Test yourself

What happens if you try to share an Rc<T> between threads?

  1. It works but is slow
  2. It doesn't compile, because Rc isn't Send
  3. It panics at runtime
  4. It causes a data race
Show answer

Answer: It doesn't compile, because Rc isn't Send

Was this page helpful?