В стандартной библиотеке Rust представлены основные примитивы синхронизации для безопасной работы с многопоточностью:
AtomicBool, AtomicUsize и др.) — операции чтения/записи без блокировок, на уровне аппаратуры;Пример:
use std::sync::{Arc, Mutex}; use std::thread; fn main() { let counter = Arc::new(Mutex::new(0)); let mut handles = vec![]; for _ in 0..10 { let counter = Arc::clone(&counter); let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); *num += 1; }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } println!("Result: {}", *counter.lock().unwrap()); }
Вопрос: Гарантирует ли Rust, что использование Mutex<T> полностью избавляет от deadlock'ов за счёт проверки на этапе компиляции?
Ответ: Нет. Rust обеспечивает безопасный доступ к данным через владение и borrow-checker, но не защищает от deadlock'ов на уровне языка. Мёртвые блокировки возникают чисто логически при нарушении порядка захвата нескольких Mutex или их рекурсивном захвате. Пример:
use std::sync::Mutex; let lock1 = Mutex::new(0); let lock2 = Mutex::new(0); // Поток 1: lock1 -> lock2, Поток 2: lock2 -> lock1 ⇒ deadlock
История
История
Mutex<Option<T>> на RwLock<T>, не учли, что writable lock может быть дольше, чем lock на чтение. В пиковой нагрузке это обернулось задержками обработки до десятков секунд из-за очередей на write.История
Программисты пытались экономить на потоках, "пушили" Arc<Mutex<_>> в сотни потоков. Из-за тонкостей работы планировщика и переиспользования mutex блокировки появлялись удивительные взаимные ожидания — производительность снизилась в 5 раз!