Nella libreria standard di Rust sono presenti i principali primitivi di sincronizzazione per un uso sicuro della multithreading:
AtomicBool, AtomicUsize e altri) — operazioni di lettura/scrittura senza lock, a livello hardware;Esempio:
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!("Risultato: {}", *counter.lock().unwrap()); }
Domanda: Garantiscono i Rust che l'uso di Mutex<T> elimina completamente i deadlock grazie al controllo in fase di compilazione?
Risposta: No. Rust garantisce un accesso sicuro ai dati tramite possesso e borrow-checker, ma non protegge dai deadlock a livello di linguaggio. I deadlock si verificano puramente logicamente quando si viola l'ordine di acquisizione di più Mutex o si acquisisce in modo ricorsivo. Esempio:
use std::sync::Mutex; let lock1 = Mutex::new(0); let lock2 = Mutex::new(0); // Thread 1: lock1 -> lock2, Thread 2: lock2 -> lock1 ⇒ deadlock
Storia
Storia
Mutex<Option<T>> a RwLock<T>, senza considerare che il lock in scrittura potrebbe richiedere più tempo del lock in lettura. Nei picchi di carico, questo ha causato ritardi di elaborazione fino a decine di secondi a causa delle code per la scrittura.Storia
I programmatori cercavano di risparmiare sui thread, "spingendo" Arc<Mutex<_>> in centinaia di thread. A causa delle sfumature del funzionamento dello scheduler e del riutilizzo dei mutex, si verificavano sorprendenti attese reciproche — le prestazioni sono diminuite di 5 volte!