Arc (Rust)

Arc<T> is an atomically reference-counted smart pointer for sharing ownership of a value across threads.

Why?

Sharing a Mutex across threads breaks Rust’s single-ownership rule. Reference counting fixes that, but the non-atomic Rc<T> isn’t thread-safe, so we need an atomic variant.

Two reference-counted smart pointers ship in std:

  • Rc<T>: shared ownership within a single thread. .clone() bumps the refcount, value drops at 0. !Send, so it can’t cross threads
  • Arc<T>: atomic refcount. Slightly slower than Rc, but Send + Sync

Typical pattern: wrap a Mutex in an Arc to get shared, protected, mutable state:

let quit = Arc::new(Mutex::new(false));
let handler_quit = Arc::clone(&quit);
ctrlc::set_handler(move || {
    let mut b = handler_quit.lock().unwrap();
    *b = true;
});

Caveats:

  • Ref cycles between Rc/Arc leak, the count never hits 0
  • Unlike C++‘s shared_ptr, you can’t keep a reference after the Arc goes out of scope; the value is owned by the pointer and freed when it drops
  • Box<T> is the simpler sibling for putting data on the heap with single ownership

Deadlock still possible

Automatic unlock doesn’t prevent deadlock. Nothing stops thread 1 taking A then B while thread 2 takes B then A.