Eine Race Condition (Wettlaufsituation) entsteht, wenn das Ergebnis eines Programms von der zeitlichen Reihenfolge konkurrierender Zugriffe auf gemeinsame Ressourcen abhängt — und diese Reihenfolge nicht vorhersehbar ist. Zwei oder mehr Threads „wetten“ gewissermaßen darum, wer zuerst liest oder schreibt. Je nach Timing liefert dasselbe Programm unterschiedliche Ergebnisse: mal korrekt, mal falsch, mal abgestürzt.
Das klassische Beispiel
Ein Zähler i soll von zwei Threads je einmal erhöht werden. Das Inkrementieren ist keine einzelne Operation, sondern ein lesen–ändern–schreiben-Zugriff:
Thread A: lädt i (= 5), erhöht auf 6, speichert 6
Thread B: lädt i (= 5), erhöht auf 6, speichert 6
Ergebnis: 6 statt 7 — ein Inkrement ging verloren
Weil beide Threads den alten Wert lesen, bevor einer den neuen speichert, geht ein Update verloren. Solche Fehler sind besonders tückisch, weil sie nur bei ungünstigem Timing auftreten und sich schwer reproduzieren lassen.
Arten und Folgen
- Daten-Race: Gleichzeitige Lese-/Schreibzugriffe auf denselben Speicherbereich ohne Synchronisation.
- TOCTOU (time-of-check to time-of-use): Zwischen Prüfung („ist die Datei noch da?“) und Nutzung („jetzt öffnen“) ändert ein anderer Prozess den Zustand — ein klassisches Sicherheitsproblem.
- Verlust von Updates in Datenbanken und Zählern, kaputte Warteschlangen, inkonsistente Buchungen.
Gegenmaßnahmen
- Atomare Operationen: compare-and-swap oder fetch-and-add führen Lesen-Ändern-Schreiben unteilbar aus.
- Synchronisation: Mutex, Semaphore und kritische Abschnitte, damit nur ein Thread zur Zeit auf die Ressource zugreift.
- Thread-lokale Daten oder unveränderliche (immutable) Datenstrukturen vermeiden geteilten Zustand von vornherein.
- Analyse-Werkzeuge: ThreadSanitizer (TSan), Valgrind/Helgrind oder der Go Race Detector finden Daten-Races zur Laufzeit.
Race Conditions sind eine typische Gefahr nebenläufiger Programme — wer Nebenläufigkeit einsetzt, muss den Zugriff auf gemeinsame Ressourcen von Threads und Prozessen bewusst synchronisieren.
Verwandte Grundlagen: Nebenläufigkeit, Thread, Prozess.