State mit Arc/Mutex teilen
Sicher geteilte Daten
State mit Arc/Mutex teilen ist eine kostenlose Learn Rust Coding-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Learn Rust Coding-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Learn Rust Coding-Kurs umfasst insgesamt 4 Lektionen.
Warum gemeinsamer Zustand schwierig ist
Manchmal reicht das Senden von Nachrichten nicht aus, und mehrere Threads müssen tatsächlich dieselben Daten lesen und schreiben. Rust erlaubt es nicht, einen veränderbaren Wert ohne Schutz zwischen Threads zu teilen, da dies zu einem Data Race führen könnte.
Die beiden Werkzeuge, die Sie kombinieren, sind:
Arcfür gemeinsamen Besitz über mehrere Threads hinweg.Mutexfür sichere, exklusive Änderungen.
Rc ist nicht threadsicher
Rc ermöglicht gemeinsamen Besitz, aber nur innerhalb eines einzelnen Threads. Sein Referenzzähler ist nicht synchronisiert, daher verweigert der Compiler die Übertragung zwischen Threads. Für die gemeinsame Nutzung in mehreren Threads benötigen Sie Arc (Atomically Reference Counted).
Arc verhält sich wie Rc, aktualisiert seinen Zähler jedoch mit atomaren Operationen, sodass Kopien über mehrere Threads hinweg sicher sind.
use std::sync::Arc;
fn main() {
let data = Arc::new(vec![1, 2, 3]);
let clone1 = Arc::clone(&data);
println!("original: {:?}", data);
println!("clone: {:?}", clone1);
println!("count: {}", Arc::strong_count(&data));
}Mutex ermöglicht exklusiven Zugriff
Ein Mutex kapselt Daten und garantiert, dass immer nur ein Thread gleichzeitig darauf zugreift. Mit .lock() erhalten Sie einen MutexGuard, der auf den enthaltenen Wert dereferenziert werden kann. Die Sperre wird automatisch freigegeben, wenn der Guard seinen Gültigkeitsbereich verlässt.
use std::sync::Mutex;
fn main() {
let m = Mutex::new(5);
{
let mut num = m.lock().unwrap();
*num += 10;
} // guard dropped here, lock released
println!("value = {:?}", m.lock().unwrap());
}Arc und Mutex kombinieren
Um veränderbare Daten über mehrere Threads hinweg zu teilen, kapseln Sie sie als Arc:
Arcermöglicht vielen Threads, ein Handle auf dieselben Daten zu besitzen.Mutexermöglicht jedem Thread, die Daten sicher und nacheinander zu verändern.
Duplizieren Sie den Arc für jeden Thread, bevor Sie ihn starten.
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let c = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut n = c.lock().unwrap();
*n += 1;
});
handle.join().unwrap();
println!("counter = {}", *counter.lock().unwrap());
}Ein gemeinsamer Zähler über mehrere Threads
Das klassische Beispiel: Zehn Threads erhöhen jeweils einen gemeinsamen Zähler. Jeder Thread besitzt eine eigene Arc-Kopie und sperrt den Mutex, um den Zähler um eins zu erhöhen. Nachdem alle Threads verbunden wurden, beträgt das Ergebnis genau 10 – ohne Data Race.
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 c = Arc::clone(&counter);
handles.push(thread::spawn(move || {
let mut num = c.lock().unwrap();
*num += 1;
}));
}
for h in handles {
h.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}Der Gültigkeitsbereich der Sperre ist wichtig
Der MutexGuard hält die Sperre, bis er verworfen wird. Wenn Sie ihn während langsamer Arbeiten behalten, blockieren Sie andere Threads. Halten Sie kritische Abschnitte kurz: sperren, ändern, freigeben. Wenn Sie die Sperre in einen kleinen Block einschließen, wird sie vor zusätzlicher Verarbeitung freigegeben.
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let log = Arc::new(Mutex::new(Vec::new()));
let mut handles = vec![];
for i in 0..3 {
let l = Arc::clone(&log);
handles.push(thread::spawn(move || {
{
let mut v = l.lock().unwrap();
v.push(i);
} // released quickly
}));
}
for h in handles { h.join().unwrap(); }
let mut result = log.lock().unwrap().clone();
result.sort();
println!("{:?}", result);
}Deadlocks: ein echtes Risiko
Ein Deadlock tritt auf, wenn zwei Threads jeweils eine Sperre halten, die der andere benötigt, und beide für immer warten. Rust verhindert Data Races, aber keine Deadlocks. Vermeiden Sie sie, indem Sie mehrere Mutexes immer in derselben Reihenfolge sperren und Sperren nur kurz halten.
Vermeiden Sie außerdem, denselben Mutex zweimal in einem Thread zu sperren; der Standard-Mutex ist nicht wiedereintrittsfähig.
Vergiftung bei einem Panic in einem Thread
Wenn ein Thread während des Haltens einer Sperre in einen Panic läuft, wird der Mutex als vergiftet markiert. Spätere Aufrufe von .lock() geben Err zurück, damit Sie wissen, dass die Daten inkonsistent sein könnten. Wenn Sie entscheiden, dass die Daten weiterhin verwendbar sind, können Sie den inneren Guard über into_inner() des Fehlers zurückgewinnen.
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let data = Arc::new(Mutex::new(0));
let d = Arc::clone(&data);
let _ = thread::spawn(move || {
let mut g = d.lock().unwrap();
*g = 7;
panic!("boom"); // poisons the mutex
}).join();
match data.lock() {
Ok(g) => println!("ok: {}", *g),
Err(poisoned) => println!("recovered: {}", *poisoned.into_inner()),
}
}RwLock für viele Leser
Wenn es deutlich mehr Lese- als Schreibzugriffe gibt, kann ein RwLock schneller sein als ein Mutex. Er erlaubt vielen gleichzeitigen Lesern oder einem Schreiber den Zugriff. Verwenden Sie .read() für gemeinsamen Zugriff und .write() für exklusiven Zugriff.
use std::sync::{Arc, RwLock};
use std::thread;
fn main() {
let config = Arc::new(RwLock::new(String::from("v1")));
let reader = Arc::clone(&config);
let r = thread::spawn(move || {
let val = reader.read().unwrap();
println!("read: {}", *val);
});
r.join().unwrap();
{
let mut w = config.write().unwrap();
*w = String::from("v2");
}
println!("final: {}", *config.read().unwrap());
}Atomics für einfache Zähler
Für einen einzelnen Ganzzahlzähler wäre ein vollständiger Mutex überdimensioniert. Typen wie AtomicUsize bieten sperrenfreie Aktualisierungen über Methoden wie fetch_add. Kapseln Sie sie in Arc, um sie über mehrere Threads hinweg zu teilen. Wählen Sie eine Ordering; SeqCst ist die einfachste sichere Standardeinstellung.
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
fn main() {
let counter = Arc::new(AtomicUsize::new(0));
let mut handles = vec![];
for _ in 0..5 {
let c = Arc::clone(&counter);
handles.push(thread::spawn(move || {
c.fetch_add(1, Ordering::SeqCst);
}));
}
for h in handles { h.join().unwrap(); }
println!("count = {}", counter.load(Ordering::SeqCst));
}Das passende Werkzeug auswählen
Kurze Orientierung für gemeinsamen Zustand:
- Channel: Besitz übertragen, im Pipeline-Stil.
- Arc<Mutex>: gemeinsam genutzte veränderbare Struktur mit gemischten Lese- und Schreibzugriffen.
- Arc<RwLock>: gemeinsam genutzte, leselastige Daten.
- Atomics: einzelne primitive Zähler oder Flags.
Bevorzugen Sie das einfachste passende Werkzeug; verwenden Sie Sperren erst, wenn sich das Problem nicht gut mit dem Senden von Nachrichten modellieren lässt.
Kurzer Test
Testen Sie Ihr Verständnis von gemeinsamem Zustand.
Zusammenfassung
Sie haben gelernt, wie Sie Zustand sicher über mehrere Threads hinweg teilen:
Arcermöglicht threadsicheren gemeinsamen Besitz;Rcnicht.Mutexermöglicht exklusive Änderungen über einen Guard, der automatisch entsperrt.Arc<Mutex<T>>ist das Standardmuster für gemeinsam genutzte veränderbare Daten.- Halten Sie Gültigkeitsbereiche von Sperren kurz und achten Sie auf Deadlocks und Vergiftung.
RwLockeignet sich für leselastige Daten; Atomics für einfache Zähler.
Häufig gestellte Fragen
Ist die Lektion „State mit Arc/Mutex teilen“ kostenlos?
Ja — der vollständige Text von „State mit Arc/Mutex teilen“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Learn Rust Coding-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Learn Rust Coding-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „State mit Arc/Mutex teilen“?
Sicher geteilte Daten Du übst Learn Rust Coding mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Learn Rust Coding zu starten?
Keine Vorkenntnisse erforderlich. Learn Rust Coding auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.
Wie lange dauert die Lektion „State mit Arc/Mutex teilen“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Learn Rust Coding-Lektion Code schreiben und ausführen?
Ja. Jede Learn Rust Coding-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- mpsc-Kanäle
- State mit Arc/Mutex teilen
- Bereichsbegrenzte Threads
- Crossbeam-Kanäle