19.7 Shared Ownership Across Threads with Arc<T>

Rc<T> is single-threaded. If you need to share data across multiple threads, Rust provides Arc<T> (Atomic Reference Counted). It functions like Rc<T> but maintains the reference count using atomic operations, ensuring it’s safe to clone and use across threads.

19.7.1 Arc<T>: Thread-Safe Reference Counting

  • Increments and decrements the reference count using atomic instructions.
  • Ensures data stays alive as long as there’s at least one Arc<T> in any thread.
  • Provides safe sharing across thread boundaries.

Example:

use std::sync::Arc;
use std::thread;

fn main() {
    let data = Arc::new(42);
    let handles: Vec<_> = (0..4).map(|_| {
        let data = Arc::clone(&data);
        thread::spawn(move || {
            println!("Data: {}", data);
        })
    }).collect();

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

19.7.2 Mutating Data Under Arc<T>

To allow mutation with shared ownership across threads, combine Arc<T> with synchronization primitives like Mutex<T> or RwLock<T>:

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

fn main() {
    let shared_num = Arc::new(Mutex::new(0));
    let handles: Vec<_> = (0..4).map(|_| {
        let shared_num = Arc::clone(&shared_num);
        thread::spawn(move || {
            let mut val = shared_num.lock().unwrap();
            *val += 1;
        })
    }).collect();

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

    println!("Final value: {}", *shared_num.lock().unwrap());
}