Theme
Q039. What does Arc<T> provide, and when should you use it?
Short Answer
Arc<T> provides shared ownership of one heap-allocated T through atomic reference counting. Cloning an Arc creates another owner of the same value; the value is dropped after the last strong owner is dropped. Use it when multiple threads or independently owned tasks must keep the same value alive. Arc solves ownership and lifetime sharing, not mutation or thread safety by itself.
Deep Dive
Ordinary ownership requires one owner, and borrowed references are limited by the owner's lifetime. Arc is useful when no single participant naturally owns the value long enough, such as shared application state captured by several spawned tasks.
Arc::clone is shallow: it does not clone T. It creates another handle to the same allocation and increments the strong count. Shared immutable access works through Deref<Target = T>. Mutation requires an additional strategy such as Mutex, RwLock, atomics, interior mutability provided by T, or message passing.
Prefer a borrow when a clear lexical owner exists. Prefer Rc for shared ownership confined to one thread. Use Arc only when ownership must cross thread boundaries or an API requires Send.
Internal Model
An Arc handle points to an allocation containing reference-count metadata and T. Strong references keep T alive. Weak references keep the allocation metadata alive without keeping T alive.
The counts are updated atomically so clones and drops can occur safely from different threads. Those atomic operations add synchronization cost compared with a borrow or Rc, but accessing T through an existing Arc does not increment the count.
Example
rust
use std::sync::Arc;
use std::thread;
fn main() {
let names = Arc::new(vec!["matching", "risk", "market-data"]);
let worker_names = Arc::clone(&names);
let worker = thread::spawn(move || {
println!("worker sees {} services", worker_names.len());
});
println!("main sees {} services", names.len());
worker.join().unwrap();
}Common Mistakes
- Saying
Arc::cloneperforms a deep clone ofT. - Using
Arcwhen a normal borrow has a clear and sufficient lifetime. - Assuming
Arc<T>permits safe concurrent mutation of anyT.
Follow-ups
- How are strong and weak reference counts different?
- When should
Rc<T>be preferred overArc<T>? - How can reference cycles prevent an
Arcallocation from being released?
Related
- Q023. Does copying a value mean that it has no ownership?
- Q040. How does
Arcwork internally, and what do clone and drop cost? - Q041. Why does
Arcnot automatically makeTthread-safe?
References
- Rust Standard Library
- The Rust Programming Language