EMZETT.
Login

Race Condition (Wettlaufsituation)

Kurz: Eine Race Condition entsteht, wenn das Ergebnis eines Programms davon abhängt, in welcher zeitlichen Reihenfolge mehrere Threads auf gemeinsame Daten zugreifen.

Genauer: Der Fehler tritt unregelmäßig auf und lässt sich schwer reproduzieren, weil die Reihenfolge von Zufälligkeiten des Schedulers abhängt. Klassisches Beispiel: zwei Threads erhöhen denselben Zähler. zaehler += 1 besteht aus Lesen, Addieren und Schreiben – wechselt der Thread dazwischen, geht eine Erhöhung verloren.

Im Detail

import threading
 
zaehler = 0
 
def zaehle():
    global zaehler
    for _ in range(100_000):
        zaehler += 1        # nicht atomar: lesen, addieren, schreiben
 
threads = [threading.Thread(target=zaehle) for _ in range(4)]
for t in threads: t.start()
for t in threads: t.join()
print(zaehler)              # oft weniger als 400000 (je nach Python-Version und Timing)

Abhilfe

sperre = threading.Lock()
 
def zaehle_sicher():
    global zaehler
    for _ in range(100_000):
        with sperre:        # nur ein Thread zur Zeit im Block
            zaehler += 1
  • Sperren (Mutex) schützen kritische Abschnitte.
  • Atomare Operationen (AtomicInteger in Java, atomic in Go/Rust/C++) erledigen Lesen und Schreiben unteilbar.
  • Unveränderliche Daten (Immutability) und Nachrichtenaustausch (Queues, Kanäle, Actors) vermeiden gemeinsamen Zustand.
  • Rust verhindert Datenrennen bereits zur Übersetzungszeit durch sein Besitzmodell.

Verwandt ist das Problem, dass Sperren selbst Fehler erzeugen können: Deadlock. Zum Aufspüren helfen Werkzeuge wie ThreadSanitizer und Go’s -race.

Siehe auch: Thread, Mutex, Deadlock, Nebenläufigkeit