Met de kwestie van veilige werking in multithreadomgevingen worden programmeurs al lange tijd geconfronteerd, waarbij ze constant problemen tegenkomen zoals racecondities, inconsistente gegevens en geheugenlekken. In Rust is er een unieke benadering geïmplementeerd met marker-traits Send en Sync, om deze problemen al in de compileerfase te minimaliseren.
Probleem — gebrek aan controle over de toegang tot gedeelde gegevens tussen threads, wat leidt tot moeilijk te traceren fouten. In veel talen ligt de verantwoordelijkheid volledig bij de programmeur, in Rust controleert de compiler zelf wat er tussen threads kan worden overgedragen/gedeeld.
Oplossing: de trait Send garandeert de mogelijkheid om een object veilig van de ene thread naar de andere te verzenden. Sync — de mogelijkheid voor gedeelde toegang tot een referentie van een object vanuit verschillende threads. Bijna alle standaardtypes in Rust implementeren automatisch deze traits, en custom types kunnen ze handmatig implementeren of verbieden via impl !Send of impl !Sync voor specifieke gevallen.
Voorbeeldcode:
use std::sync::{Arc, Mutex}; use std::thread; 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(); } // counter zal altijd gelijk zijn aan 10 zonder races!
Belangrijke kenmerken:
Kan een type met onveilige pointers Send of Sync zijn?
Nee, als een type een raw pointer of middelen zonder garanties voor threadveiligheid bevat, implementeert het deze traits niet, of de ontwikkelaar moet ze handmatig implementeren met volledige verantwoordelijkheid (meestal met unsafe impl Send/Sync).
Zijn Rc<T> en RefCell<T> Send of Sync?
Nee, Rc<T> en RefCell<T> zijn onveilig voor multithreadgebruik (noch Send, noch Sync). Voor multithreadscenario's worden Arc<T> en Mutex/ RwLock gebruikt.
Wat gebeurt er als een static variabele een type bevat zonder geïmplementeerd Sync?
Rust laat zo'n static variabele niet bestaan: het moet Sync zijn, anders zal de compiler een foutmelding genereren.
Een jonge ontwikkelaar plaatst een Rc-object in thread::spawn — de code compileert alleen als Rc niet tussen threads wordt doorgegeven. Wanneer geprobeerd wordt om Rc uit thread::spawn te halen, ontstaat er een compileerfout omdat Rc Send niet implementeert en niet beschermd is tegen races.
Voordelen:
Nadelen:
Arc+Mutex wordt gebruikt voor een multithread teller, alle threads werken met dezelfde gegevens via een threadveilige interface. Er zijn geen races, de code is veilig en robuust.
Voordelen:
Nadelen: