Shared State: Arc and Mutex
When you need shared mutable state across threads, use Arc (Atomic Reference Counting) for sharing and Mutex for safe mutation.
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
// Mutex: mutual exclusion - only one thread at a time
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter); // Cheap: increments ref count
let h = thread::spawn(move || {
let mut num = counter.lock().unwrap(); // Acquire lock (blocks)
*num += 1;
// Lock released when `num` drops at end of block
});
handles.push(h);
}
for h in handles { h.join().unwrap(); }
println!("Final count: {}", *counter.lock().unwrap()); // 10
// RwLock: multiple readers OR one writer
use std::sync::RwLock;
let data = Arc::new(RwLock::new(vec![1, 2, 3]));
let data_clone = Arc::clone(&data);
thread::spawn(move || {
let mut v = data_clone.write().unwrap(); // Exclusive write
v.push(4);
}).join().unwrap();
let readers = vec![Arc::clone(&data), Arc::clone(&data)];
for d in readers {
thread::spawn(move || {
let v = d.read().unwrap(); // Multiple reads allowed simultaneously
println!("{:?}", *v);
}).join().unwrap();
}
}Avoiding Deadlocks
use std::sync::{Arc, Mutex};
// Deadlock-safe pattern: always acquire locks in same order
fn transfer(from: &Mutex, to: &Mutex, amount: f64) {
let mut f = from.lock().unwrap();
let mut t = to.lock().unwrap();
if *f >= amount { *f -= amount; *t += amount; }
}
// Minimize lock scope - hold for as little time as possible
fn process_quickly(data: &Arc>>) {
let item = {
let locked = data.lock().unwrap();
locked.first().cloned() // Extract data
// Lock released here
};
// Do processing outside the lock
if let Some(x) = item { println!("Processing: {}", x * 2); }
} 🎯 Practice
- Implement a thread-safe counter with Arc<Mutex<i64>> - increment from 10 threads simultaneously
- Implement a shared cache: Arc<RwLock<HashMap<String, String>>> with concurrent readers and occasional writer
🎉 Key Takeaways
- Arc = thread-safe reference counting; Mutex = mutual exclusion lock
- Arc::clone() increments the ref count cheaply; data freed when count hits 0
- RwLock allows multiple concurrent readers OR one exclusive writer
- Minimize lock scope; acquire locks in consistent order to prevent deadlocks