La bibliothèque standard de Rust propose des primitives de synchronisation fondamentales pour une utilisation sûre de la concurrence :
AtomicBool, AtomicUsize, etc.) — opérations de lecture/écriture sans verrouillage, au niveau matériel ;Exemple :
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!("Résultat : {}", *counter.lock().unwrap()); }
Question : Rust garantit-il que l'utilisation de Mutex<T> élimine complètement les deadlocks grâce à une vérification lors de la compilation ?
Réponse : Non. Rust assure un accès sûr aux données via la propriété et le borrow-checker, mais ne protège pas des deadlocks au niveau du langage. Les blocages morts surviennent logiquement en cas de violation de l'ordre de capture de plusieurs Mutex ou de leur capture récursive. Exemple :
use std::sync::Mutex; let lock1 = Mutex::new(0); let lock2 = Mutex::new(0); // Thread 1 : lock1 -> lock2, Thread 2 : lock2 -> lock1 ⇒ deadlock
Histoire
Histoire
Mutex<Option<T>> à RwLock<T>, sans tenir compte du fait que le verrou d'écriture pouvait être plus long qu'un verrou de lecture. Pendant les pics de charge, cela a entraîné des délais de traitement allant jusqu'à des dizaines de secondes en raison des files d'attente pour écrire.Histoire
Les programmeurs ont essayé d'économiser sur les threads, "poussant" Arc<Mutex<_>> dans des centaines de threads. En raison des subtilités du fonctionnement du planificateur et du réutilisation des mutex, des attentes mutuelles surprenantes sont apparues - la performance a chuté de 5 fois !