Historiquement, le travail avec la multithreading était accompagné d'accidents, de courses et de fuites, en particulier lors d'échanges de mémoire incontrôlés. Rust implémente le concept de sécurité des threads au niveau des types : un objet peut être transmis à un thread uniquement s'il implémente les traits nécessaires (Send, Sync). Les threads eux-mêmes sont créés via std::thread::spawn, et la communication entre eux se fait par des canaux ou de la mémoire partagée avec mutation contrôlée (Mutex, Arc).
Problème: gérer manuellement la synchronisation est difficile et dangereux. La transmission d'objets arbitraires entre les threads sans transfert explicite de propriété entraîne des courses et des plantages.
Solution: seuls les objets explicitement déplacés (move) ou partagés via Arc, Mutex, ainsi que les canaux de messages intégrés (std::sync::mpsc, crossbeam) sont permis. Cela minimise les erreurs dues à l'échange de données synchrones et asynchrones : la propriété est toujours claire.
Exemple de code :
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); }
Caractéristiques clés :
Peut-on continuer à utiliser un objet dans le thread principal après l'avoir transmis via move ?
Non, une fois qu'un objet est déplacé (par exemple, dans une closure dans thread::spawn), il n'est plus utilisable dans le thread parent, le compilateur ne permettra pas la compilation du code.
Peut-on transmettre des références mutables (&mut T) entre les threads ?
Non, une référence mutable &mut T ne peut exister que dans une seule instance, et le trait Send n'est pas implémenté par défaut pour elle. Les données modifiables doivent être enveloppées via Mutex/Arc.
Pourquoi ne peut-on pas utiliser Rc<T> pour partager la propriété entre les threads ?
Rc<T> n'implémente pas Sync et Send, car son compteur interne n'est pas thread-safe. Pour la sécurité des threads, on utilise Arc<T> (compteur de références atomique).
// Comparaison Rc et Arc use std::sync::Arc; let x = Arc::new(5); // peut être cloné et partagé entre les threads
Un développeur a décidé de partager une chaîne entre les threads en utilisant Rc<String>, en plaçant Rc à l'intérieur de thread::spawn. Le code ne compile que s'il est forcé par unsafe, après quoi l'application peut planter ou travailler avec des données corrompues.
Avantages :
Inconvénients :
Utilisation de Arc<String> + Mutex<String> pour un accès protégé, ou transmission de messages via un canal, sans propriété partagée.
Avantages :
Inconvénients :