Ответ 1
Arc
, конечно, является наиболее распространенным в этом контексте, но существуют другие типы указателей, которые разрешают совместное использование. Основной (и наиболее распространенный, в остальной части Rust) один является общей ссылкой &T
. Обычно это не работает с тегами std::thread::spawn
'd, потому что обычно указывает на данные, управляемые каким-то другим потоком, и, как правило, это не 'static
(особенно это относится к &Mutex<T>
). Однако для создания потока, который может обмениваться данными со своим родителем, можно использовать scoped thread. Например.
extern crate crossbeam;
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);
});
println!("{:?}", *data.lock().unwrap());
// one of [0, 1, 2, 3] or [0, 1, 3, 2]
}
Тип data
в замыкании, переданном на scope.spawn
, на самом деле &Mutex<Vec<i32>>
(так как он не имеет ключевого слова move
, то закрытие использует стиль захвата по умолчанию: по ссылке).
&
и Arc
- это те, которые могут достичь такого рода потокобезопасного совместного использования в стандартной библиотеке/языке, но также можно писать типы указателей, которые обеспечивают поточно-безопасный обмен во внешних библиотеках.
Однако, удаляясь от шаблона Pointer<Mutex<...>>
, может быть полезно, чтобы мьютекс и разделение разделялись, например. Arc<Vec<Mutex<T>>>
позволяет делиться некоторым количеством Mutex<T>
без необходимости Arc
каждого отдельно, или, может быть, нужно иметь некоторую абстракцию вокруг Mutex
, и поэтому оберните ее в struct
:
struct Wrapped {
data: Mutex<T>
}
impl Wrapped {
// fancy methods that abstract over `data.lock()`
}
Вероятно, тогда можно увидеть Arc<Wrapped>
(или какой-нибудь другой указатель, который разрешает совместное использование).