Rc<RefCell<T>> / Arc<Mutex<T>>
Rc<RefCell<T>> is a pattern for multiple ownership with interior mutability in a single-threaded context. Arc<Mutex<T>> is a pattern for thread-safe multiple ownership with interior mutability in a multi-threaded context.
Syntax
use std::rc::Rc;
use std::cell::RefCell;
use std::sync::{Arc, Mutex};
// Single-threaded: multiple ownership + interior mutability
let shared = Rc::new(RefCell::new(value));
let clone = Rc::clone(&shared);
*shared.borrow_mut() = new_value;
// Multi-threaded: thread-safe multiple ownership + interior mutability
let shared = Arc::new(Mutex::new(value));
let clone = Arc::clone(&shared);
let mut guard = shared.lock().unwrap();
*guard = new_value;
Combination Overview
| Pattern | Thread | Description |
|---|---|---|
| Rc<RefCell<T>> | Single only | Reference-counted sharing with runtime borrow checking for mutability. |
| Arc<Mutex<T>> | Multi-thread | Atomic reference-counted sharing with exclusive access via Mutex. |
| Arc<RwLock<T>> | Multi-thread | Multiple threads can acquire a read-only lock simultaneously. |
Sample Code
use std::rc::Rc;
use std::cell::RefCell;
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
// Rc<RefCell<T>>: append to a shared list in a single thread.
let list = Rc::new(RefCell::new(vec![]));
let list_a = Rc::clone(&list);
let list_b = Rc::clone(&list);
list_a.borrow_mut().push(1);
list_b.borrow_mut().push(2);
list.borrow_mut().push(3);
println!("{:?}", list.borrow()); // [1, 2, 3]
// Arc<Mutex<T>>: share a counter across multiple threads.
let counter = Arc::new(Mutex::new(0));
let handles: Vec<_> = (0..5).map(|_| {
let cnt = Arc::clone(&counter);
thread::spawn(move || {
let mut n = cnt.lock().unwrap();
*n += 1; // Acquire the Mutex lock before modifying the value.
})
}).collect();
for h in handles {
h.join().unwrap();
}
println!("counter: {}", *counter.lock().unwrap()); // counter: 5
}
Overview
In Rust, no single smart pointer can satisfy the need to mutate a value from multiple owners, so combining smart pointers is a common pattern. Rc<RefCell<T>> is the standard choice for single-threaded code, while Arc<Mutex<T>> is the standard choice for multi-threaded code.
To prevent forgotten lock releases, Rust's Mutex is designed so that the guard (MutexGuard) automatically releases the lock when it goes out of scope.
Locking multiple Mutexes in different orders can cause a deadlock. When multiple locks are needed, always design your code to acquire them in a consistent order.
If you find any errors or copyright issues, please contact us.