An extremely common pattern in Rust is Arc
, where Arc
provides the memory management, and Mutex
provides safe multi-
Arc
is of course the most common one in this context, but there are other pointer types that allow sharing. The major (and most common, in the rest of Rust) one is the shared reference &T
. This normally doesn't work with std::thread::spawn
'd threads, because it generally points to data controlled by some other thread, and is hence usually not 'static
(particularly so when it is a &Mutex<T>
). However, one can use a scoped thread to create a thread that can share data with its parent. E.g.
use crossbeam; // 0.7.3
use std::sync::Mutex;
fn main() {
let data = Mutex::new(vec![0, 1]);
crossbeam::scope(|scope| {
// these run concurrently:
let _guard = scope.spawn(|_| {
data.lock().unwrap().push(2);
});
data.lock().unwrap().push(3);
})
.unwrap();
println!("{:?}", data.lock().unwrap());
// one of [0, 1, 2, 3] or [0, 1, 3, 2]
}
The type of data
in the closure passed to scope.spawn
is in fact &Mutex<Vec<i32>>
(since it doesn't have the move
keyword the closure is using the default capturing style: by reference).
&
and Arc
are the two that can achieve this sort of thread-safe sharing in the standard library/language, but one can also write pointer types that offer thread-safe sharing in external libraries.
However, moving away from the Pointer<Mutex<...>>
pattern, it can be useful to have the mutex and the sharing separated, e.g. Arc<Vec<Mutex<T>>>
allows one to share some number of Mutex<T>
's without having to Arc
each one individually, or maybe one wants to have some abstraction around a Mutex
, and so wrap it in a struct
:
struct Wrapped {
data: Mutex<T>,
}
impl Wrapped {
// fancy methods that abstract over `data.lock()`
}
One would likely then see Arc<Wrapped>
(or some other pointer that allows sharing).