← SEARCHABLE ARCHIVE
Operating System · 2026-07-15

Thread-Synchronisation und Race-Bedingungen

Warum ändern sich die Ergebnisse freigegebener Daten jedes Mal, wenn ich es ausführe?

INTERACTIVE READING MODE →

Die in diesem Blog verfassten Artikel wurden mit dem Ziel erstellt, zu unterrichten. Außerdem können die Informationen im Artikel falsch sein, also seien Sie bitte vorsichtig.

Threads im selben Prozess teilen Heap- und globale Daten. Dadurch können Daten schnell ausgetauscht werden. Wenn jedoch derselbe Wert gleichzeitig gelesen und geschrieben wird, können die Ergebnisse bei jeder Ausführung variieren.

Dieses Problem wird Race Condition genannt.

count++ ist kein einmaliger Vorgang

int count = 0;

void AddCount()
{
    ++count;
}

Es mag eine einzige Codezeile sein, aber auf der CPU könnten es mehrere Schritte sein: einen Wert lesen, 1 hinzufügen und ihn erneut speichern.

Thread A liest Anzahl 0
Thread B liest Anzahl 0
Thread A speichert 1
Thread B speichert 1

Wir erhöhen es zweimal, aber das Endergebnis ist 1, nicht 2. Da die Ausführungsreihenfolge von Threads je nach Betriebssystemsituation variiert, handelt es sich möglicherweise um einen Fehler, der beim Testen nur gelegentlich auftritt.

Mutex erlaubt jeweils nur den Eintritt eines Threads

std::mutex countMutex;
int count = 0;

void AddCount()
{
    std::lock_guard<std::mutex> lock(countMutex);
    ++count;
}

Während der Thread, der den Mutex gesperrt hat, den kritischen Abschnitt ausführt, warten andere Threads. lock_guardWenn Sie verwenden, wird die Sperre automatisch aufgehoben, auch wenn die Funktion beendet wird oder eine Ausnahme auftritt.

Atomic kann für einfache Werte verwendet werden

Atomare Operationen können für kleine Operationen verwendet werden, beispielsweise zum Erhöhen einer Ganzzahl.

std::atomic<int> count = 0;

void AddCount()
{
    ++count;
}

Wenn jedoch die Beziehungen zwischen mehreren Variablen gleichzeitig sicher aufrechterhalten werden müssen, kann dies nicht mit nur einem Atom gelöst werden. Wenn beispielsweise Goldabzug und Gegenstandszugabe gemeinsam gelingen müssen, müssen beide durch einen einzigen kritischen Bereich geschützt werden.

Sie sollten auch auf Deadlocks achten

Wenn zwei Threads auf eine vom anderen gehaltene Sperre warten, kann niemand fortfahren. Dies wird als Deadlock bezeichnet.

Thread A: Hält Lock 1 und wartet auf Lock 2
Thread B: Hält Lock 2 und wartet auf Lock 1

Sie müssen sich angewöhnen, Sperren immer in der gleichen Reihenfolge zu erwerben und keine langwierigen Aufgaben auszuführen, während Sie die Sperre halten.

Der Sinn von Multithreading besteht nicht darin, viele Threads zu erstellen. Reduzieren Sie die Anzahl der geteilten Daten, definieren Sie klar den Umfang dessen, was geteilt werden muss, und verwenden Sie ein Synchronisierungstool, das diesem Umfang entspricht.