0Pricing
C++ Academy · Lektion

Bedingungsvariablen und Arbeitermuster

Koordinieren Sie Threads mit std::condition_variable und dem klassischen Worker-Pool-Muster.

Bedingungsvariablen und Arbeitermuster ist eine kostenlose C++ Academy-Lektion auf CoddyKit. Dies ist Lektion 3 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 C++ Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der C++ Academy-Kurs umfasst insgesamt 4 Lektionen.

Was ist eine Bedingungsvariable?

Eine Bedingungsvariable ermöglicht es einem Thread, zu warten, bis ein anderer Thread signalisiert, dass sich eine Bedingung geändert hat. Sie wird zur Koordination von Produzenten und Konsumenten verwendet.

Grundlagen von std::condition_variable

Eine Bedingungsvariable arbeitet mit einem std::mutex und einem Prädikat. Der wartende Thread gibt die Sperre während des Wartens frei und erwirbt sie beim Aufwachen erneut.

#include <condition_variable>
#include <mutex>
#include <queue>

std::mutex mtx;
std::condition_variable cv;
std::queue<int> tasks;
bool done = false;

Auf eine Bedingung warten

Verwenden Sie cv.wait(lock, predicate). Dabei wird der Mutex atomar entsperrt und der Thread schläft, bis er benachrichtigt wird. Beim Aufwachen sperrt er den Mutex erneut und prüft das Prädikat; ist es falsch, schläft er wieder.

std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return !tasks.empty() || done; });

Benachrichtigen

Der Producer-Thread ruft nach der Zustandsänderung cv.notify_one() oder cv.notify_all() auf. Während der Zustandsänderung sollte der Lock gehalten werden.

{
    std::lock_guard<std::mutex> lock(mtx);
    tasks.push(42);
}
cv.notify_one();

Producer-Consumer-Muster

Klassisches Beispiel: Producer stellen Aufgaben in die Warteschlange, Consumer warten auf Aufgaben.

void consumer() {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return !tasks.empty() || done; });
        if (done && tasks.empty()) break;
        int task = tasks.front();
        tasks.pop();
        lock.unlock();
        process(task);
    }
}

Spurious Wakeups

Ein Thread, der auf einer Condition Variable wartet, kann ohne Benachrichtigung aufgeweckt werden. Deshalb akzeptiert wait ein Prädikat – es wird bei jedem Aufwecken erneut geprüft.

notify_one vs notify_all

Verwenden Sie notify_one, wenn ein wartender Thread fortfahren kann. Verwenden Sie notify_all, wenn eine Zustandsänderung alle wartenden Threads betrifft, etwa bei einem Shutdown-Signal.

Zeitgesteuerte Wartezeiten

wait_for(lock, duration) und wait_until(lock, time_point) werden entweder durch eine Benachrichtigung oder nach Ablauf eines Timeouts beendet.

if (cv.wait_for(lock, 1s, [] { return ready; })) {
    /* condition met */
} else {
    /* timed out */
}

Grundgerüst eines Worker-Pools

Ein häufig verwendetes Muster: Eine feste Anzahl von Worker-Threads entnimmt Aufgaben aus einer gemeinsam genutzten Warteschlange. Verwenden Sie dafür Mutex + condition_variable + queue + atomare Stop-Flagge.

Vermeiden von Lost Wakeups

Ändern Sie den gemeinsam genutzten Zustand immer und rufen Sie notify_* auf, während der Mutex während der Zustandsänderung gehalten wird. Es ist in Ordnung, ihn unmittelbar vor der Benachrichtigung freizugeben, solange die Reihenfolge gewährleistet ist. Andernfalls kann ein wartender Thread die Benachrichtigung verpassen.

std::counting_semaphore (C++20)

Für einfache, auf Zählwerten basierende Signalisierung wurde in C++20 std::counting_semaphore eingeführt – für bestimmte Muster ist es einfacher als Condition Variables.

Vorsicht vor Deadlocks

Wenn Sie während des Wartens auf eine Condition Variable mehrere Locks halten, kann ein Deadlock entstehen. Erwerben Sie Locks in einer konsistenten Reihenfolge und verwenden Sie std::scoped_lock für mehrere Mutexes.

Kurze Überprüfung

Warum akzeptiert cv.wait(lock, predicate) ein Prädikat, obwohl Sie lediglich auf eine Benachrichtigung warten möchten?

Zusammenfassung

Eine Condition Variable koordiniert Threads, die auf eine Zustandsänderung warten. Verwenden Sie wait(lock, predicate), um Spurious Wakeups zu behandeln, ändern Sie den Zustand unter dem Mutex und rufen Sie anschließend notify_one oder notify_all auf.

Häufig gestellte Fragen

Ist die Lektion „Bedingungsvariablen und Arbeitermuster“ kostenlos?

Ja — der vollständige Text von „Bedingungsvariablen und Arbeitermuster“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des C++ Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der C++ Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Bedingungsvariablen und Arbeitermuster“?

Koordinieren Sie Threads mit std::condition_variable und dem klassischen Worker-Pool-Muster. Du übst C++ Academy 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 C++ Academy zu starten?

Keine Vorkenntnisse erforderlich. C++ Academy 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 3 von 4.

Wie lange dauert die Lektion „Bedingungsvariablen und Arbeitermuster“?

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 C++ Academy-Lektion Code schreiben und ausführen?

Ja. Jede C++ Academy-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

  1. std::thread: Zusammenführen und Loslösen
  2. std::mutex, lock_guard und unique_lock
  3. Bedingungsvariablen und Arbeitermuster
  4. Grundlagen von std::async und std::future
← Zurück zu C++ Academy