Condition Variables

Bei der Verwendung von threads ist es manchmal sinnvoll, daß ein thread auf einen anderen thread wartet, bis dieser mit dem Prozessieren einer Aufgabe beendet ist, d.h. daß Signale zwischen den threads ausgetauscht werden sollten. Dies kann im Prinzip mit der Verwendung von mutexes geschehen, ist aber etwas umständlich. Oder eine globale boolean Variable notified könnte z.B. auf true gesetzt werden, wenn ein Signal gesendet werden soll. Der andere thread kann in einer Schleife diese Variable notified überprüfen und bricht die Schleife ab und fährt fort, falls notified auf true gesetzt wurde. Allerdings verbraucht der wartende thread aufgrund der Schleife unnötige CPU-Zeit. Mit einem zusätzlichen sleep_for innerhalb der Schleife könnte die CPU die meiste Zeit in den Leerlauf gesetzt werden.

Eine elegantere Methode ist allerdings einen Aufruf von wait hinzuzufügen, der auf eine condition variable innerhalb der Schleife wartet:


#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <queue>
using namespace std;

condition_variable cond_var;
mutex m;

int main() {
    int value = 100;
    bool notified = false;
    thread reporter([&]() {
        
        unique_lock<mutex> lock(m);
        while (!notified) {
            cond_var.wait(lock);
        }
        
        cout << "The value is " << value << endl;
    });

    thread assigner([&]() {
        value = 20;
        
        notified = true;
        cond_var.notify_one();
        
    });

    reporter.join();
    assigner.join();
    return 0;
}

Das Beispielprogramm verwendet die neue C++11-Syntax, die es erlaubt eine thread Funktion direkt als anonyme Funktion zu definieren. Diese anonyme Funktion wird im lokalen scope definiert und kann damit auf die Variablen value und notified zugreifen.

Ohne condition variable würde das Programm in den meisten Fällen 100 ausgeben.

Mit condition variable wartet der thread reporter auf den thread assigner, der den Wert 20 setzt. Im thread assigner wird notified auf true gesetzt und das Signal über die conditions Variable cond_var gesendet. Im thread reporter wird eine Schleife solange ausgeführt solange notified den Wert false hat und in jeder Iteration wird auf das Signal gewartet.

Die Verwendung von notified in einer Schleife im thread reporter ist eigentlich ``doppelt gemoppelt'', und nur zusätzliche Absicherung falls notfiy_one anderswo gesetzt wird.


GDuckeck 2019-08-01