Исторически работа с многопоточностью сопровождалась авариями, гонками и утечками, особенно при неконтролируемом обмене памятью. Rust реализует концепцию безопасности потоков на уровне типов — объект можно передать в поток только если он реализует необходимый трейты (Send, Sync). Сами потоки создаются через std::thread::spawn, а общение между ними осуществляется через каналы или разделяемую память с контролируемой мутацией (Mutex, Arc).
Проблема: вручную управлять синхронизацией сложно и опасно. Передача произвольных объектов между потоками без явной передачи владения приводит к гонкам и краху.
Решение: только явно перемещаемые (move) объекты или разделяемые через Arc, Mutex, а также встроенные каналы сообщений (std::sync::mpsc, crossbeam). Это минимизирует ошибки, связанные с синхронным и асинхронным обменом данными: владение всегда однозначно.
Пример кода:
use std::thread; use std::sync::mpsc; fn main() { let (tx, rx) = mpsc::channel(); thread::spawn(move || { tx.send(String::from("Hello from thread!")).unwrap(); }); let received = rx.recv().unwrap(); println!("Received: {}", received); }
Ключевые особенности:
Можно ли после передачи объекта через move продолжать использовать его в основном потоке?
Нет, как только объект перемещён (например, в closure в thread::spawn), использовать его в родительском потоке невозможно, компилятор не даст собрать код.
Можно ли передавать мутируемые ссылки (&mut T) между потоками?
Нет, мутируемая ссылка &mut T может существовать только в одном экземпляре, и trait Send на нее не реализован по умолчанию. Для работы с изменяемыми данными используется обёртка через Mutex/Arc.
Почему нельзя использовать Rc<T> для разделения владения между потоками?
Rc<T> не реализует Sync и Send, так как его внутренний счётчик не потокобезопасен. Для thread-safe используется Arc<T> (atomic reference counter).
// Сравнение Rc и Arc use std::sync::Arc; let x = Arc::new(5); // можно клонировать и делить между потоками
Разработчик решил разделить строку между потоками с помощью Rc<String>, кладёт Rc внутрь thread::spawn. Код компилируется только если force-кастится через unsafe, после чего приложение может падать или работать с повреждёнными данными.
Плюсы:
Минусы:
Используется Arc<String> + Mutex<String> для защищённого доступа, либо передача сообщения через канал, без общего владения.
Плюсы:
Минусы: