C++-Standardbibliothek<condition_variable>

In der Multithread-Programmierung ist die Synchronisation zwischen Threads ein sehr wichtiges Thema.

Der C++11-Standard führte ein<condition_variable>Die Header-Datei bietet einen Mechanismus, der es Threads ermöglicht, anzuhalten, wenn bestimmte Bedingungen nicht erfüllt sind, bis andere Threads ihnen mitteilen, dass die Bedingungen erfüllt wurden.

condition_variableEs ist ein fortgeschrittenes Werkzeug zur Synchronisation zwischen Threads, das sicherer und bequemer ist als die Verwendung von Synchronisationsprimitiven auf niedriger Ebene (wie Mutexe und Bedingungsvariablen).

condition_variableEs ist eine Klassenvorlage, die verwendet wird, um die Synchronisation zwischen Threads in einer Multithread-Umgebung zu implementieren. Sie ermöglicht es einem oder mehreren Threads, darauf zu warten, dass eine bestimmte Bedingung wahr wird, während andere Threads diese wartenden Threads aufwecken können.

Syntax

Die folgenden sindcondition_variableGrundlegende Syntax:

#include <condition_variable>

void notify_one() {
    // 唤醒一个等待的线程
}

void notify_all() {
    // 唤醒所有等待的线程
}

template <class Mutex>
class condition_variable {
public:
    condition_variable();
    ~condition_variable();

    void wait(unique_lock<mutex>& lock);
    void wait_for(unique_lock<mutex>& lock, chrono::duration<Rep, Period> const& rel_time);
    void wait_until(unique_lock<mutex>& lock, chrono::time_point<Clock, Duration> const& abs_time);

    void notify_one() noexcept;
    void notify_all() noexcept;
};

Beispiel

Nachfolgend ein Beispiel unter Verwendung voncondition_variableEin einfaches Beispiel dafür, das die grundlegende Implementierung des Erzeuger-Verbraucher-Problems demonstriert.

Beispiel

#include <iostream>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <thread>

std::mutex mtx;
std::condition_variable cv;
std::queue<int> product;

void producer(int id) {
    for (int i = 0; i < 5; ++i) {
        std::unique_lock<std::mutex> lck(mtx);
        product.push(id * 100 + i);
        std::cout << "Produzent " << id << " produzierte " << product.back() << std::endl;
        cv.notify_one();
        lck.unlock();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

void consumer(int id) {
    while (true) {
        std::unique_lock<std::mutex> lck(mtx);
        cv.wait(lck, []{ return !product.empty(); });
        if (!product.empty()) {
            int prod = product.front();
            product.pop();
            std::cout << "Verbraucher " << id << " verbraucht " << prod << std::endl;
        }
        lck.unlock();
    }
}

int main() {
    std::thread producers[2];
    std::thread consumers[2];

    for (int i = 0; i < 2; ++i) {
        producers[i] = std::thread(producer, i + 1);
    }

    for (int i = 0; i < 2; ++i) {
        consumers[i] = std::thread(consumer, i + 1);
    }

    for (int i = 0; i < 2; ++i) {
        producers[i].join();
        consumers[i].join();
    }

    return 0;
}

Die Ausgabe dieses Programms kann variieren, da sie von der Thread-Planung abhängt. Sie werden jedoch sehen, wie der Produzent Elemente produziert und der Konsument sie dann konsumiert. Die Ausgabe wird ähnlich sein wie:

Producer 1 produced 100
Producer 2 produced 200
Consumer 1 consumed 100
Producer 1 produced 101
Consumer 2 consumed 200
Producer 2 produced 201
Consumer 1 consumed 101
...

Hinweise

  • Nutzungcondition_variableDabei müssen Sie sicherstellen, dass der Mutex vor dem Warten erworben und nach dem Aufwachen freigegeben wird.
  • wait、wait_forundwait_untilDie Funktionen geben den Mutex frei und erwerben ihn während des Wartens erneut.
  • notify_oneweckt einen wartenden Thread auf, währendnotify_allweckt alle wartenden Threads auf.
Weitere Erweiterungen