Namensräume
Varianten
Aktionen

std::condition_variable::wait

Von cppreference.com
 
 
Bibliothek für nebenläufige Programmierung
Threads
(C++11)
(C++20)
this_thread Namespace
(C++11)
(C++11)
(C++11)
Kooperatives Beenden
Gegenseitiger Ausschluss
(C++11)
Allgemeines Sperrungsmanagement
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
Bedingungsvariablen
(C++11)
Semaphoren
Latches und Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
(C++11)
Sichere Wiederherstellung
(C++26)
Hazard Pointer
Atomare Typen
(C++11)
(C++20)
Initialisierung von atomaren Typen
(C++11)(veraltet in C++20)
(C++11)(veraltet in C++20)
Speicherordnung
(C++11)(deprecated in C++26)
Freie Funktionen für atomare Operationen
Freie Funktionen für atomare Flags
 
 
void wait( std::unique_lock<std::mutex>& lock );
(1) (seit C++11)
template< class Predicate >
void wait( std::unique_lock<std::mutex>& lock, Predicate pred );
(2) (seit C++11)

wait veranlasst den aktuellen Thread zu blockieren, bis die Bedingungsvariable benachrichtigt wird oder ein sporadisches Aufwachen auftritt. pred kann optional angegeben werden, um sporadisches Aufwachen zu erkennen.

1) Ruft atomar lock.unlock() auf und blockiert auf *this.
Der Thread wird entsperrt, wenn notify_all() oder notify_one() ausgeführt wird. Er kann auch sporadisch entsperrt werden.
Wenn entsperrt, ruft lock.lock() auf (möglicherweise blockierend auf dem Lock) und gibt dann zurück.
2) Äquivalent zu
while (!pred())
    wait(lock);
.
Diese Überladung kann verwendet werden, um sporadische Aufwachvorgänge zu ignorieren, während auf eine bestimmte Bedingung gewartet wird, die true wird.

Unmittelbar nach der Rückgabe von wait ist lock.owns_lock() true, und lock.mutex() ist vom aufrufenden Thread gesperrt. Wenn diese Nachbedingungen nicht erfüllt werden können[1], wird std::terminate aufgerufen.

Wenn eine der folgenden Bedingungen erfüllt ist, ist das Verhalten undefiniert

  • lock.owns_lock() ist false.
  • lock.mutex() ist nicht vom aufrufenden Thread gesperrt.
  • Wenn andere Threads ebenfalls auf *this warten, ist lock.mutex() anders als der Mutex, der von den Wartefunktionen (wait, wait_for und wait_until) entsperrt wurde, die auf *this von diesen Threads aufgerufen wurden.
  1. Dies kann passieren, wenn das erneute Sperren des Mutex eine Ausnahme auslöst.

Inhalt

[bearbeiten] Parameter

lock - ein Lock, der vom aufrufenden Thread gesperrt sein muss
pred - das Prädikat, um zu überprüfen, ob das Warten abgeschlossen werden kann
Typanforderungen
-
Predicate muss die Anforderungen an ein FunctionObject erfüllen.
-
pred() muss ein gültiger Ausdruck sein, und sein Typ und seine Wertkategorie müssen die BooleanTestable-Anforderungen erfüllen.

[bearbeiten] Ausnahmen

1) Wirft nichts.
2) Jede Ausnahme, die von pred ausgelöst wird.

[bearbeiten] Anmerkungen

Die Effekte von notify_one()/notify_all() und jeder der drei atomaren Teile von wait()/wait_for()/wait_until() (entsperren+warten, aufwecken und sperren) finden in einer einzigen Gesamtordnung statt, die als Modifikationsordnung einer atomaren Variablen betrachtet werden kann: Die Ordnung ist spezifisch für diese einzelne Bedingungsvariable. Dies macht es unmöglich, dass notify_one() beispielsweise verzögert wird und einen Thread aufweckt, der kurz nach dem Aufruf von notify_one() zu warten begonnen hat.

[bearbeiten] Beispiel

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <thread>
 
std::condition_variable cv;
std::mutex cv_m; // This mutex is used for three purposes:
                 // 1) to synchronize accesses to i
                 // 2) to synchronize accesses to std::cerr
                 // 3) for the condition variable cv
int i = 0;
 
void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cerr << "Waiting... \n";
    cv.wait(lk, []{ return i == 1; });
    std::cerr << "...finished waiting. i == 1\n";
}
 
void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lk(cv_m);
        std::cerr << "Notifying...\n";
    }
    cv.notify_all();
 
    std::this_thread::sleep_for(std::chrono::seconds(1));
 
    {
        std::lock_guard<std::mutex> lk(cv_m);
        i = 1;
        std::cerr << "Notifying again...\n";
    }
    cv.notify_all();
}
 
int main()
{
    std::thread t1(waits), t2(waits), t3(waits), t4(signals);
    t1.join(); 
    t2.join(); 
    t3.join();
    t4.join();
}

Mögliche Ausgabe

Waiting...
Waiting...
Waiting...
Notifying...
Notifying again...
...finished waiting. i == 1
...finished waiting. i == 1
...finished waiting. i == 1

[bearbeiten] Fehlerberichte

Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
LWG 2114
(P2167R3)
C++11 Konvertierbarkeit in bool war zu schwach, um die Erwartungen der Implementierungen widerzuspiegeln Anforderungen verstärkt
LWG 2135 C++11 Das Verhalten war unklar, wenn lock.lock() eine Ausnahme auslöste in diesem Fall wird std::terminate aufgerufen

[bearbeiten] Siehe auch

blockiert den aktuellen Thread, bis die Bedingungsvariable geweckt wird oder nach Ablauf der angegebenen Timeout-Dauer
(public member function) [bearbeiten]
blockiert den aktuellen Thread, bis die Bedingungsvariable geweckt wird oder bis der angegebene Zeitpunkt erreicht ist
(public member function) [bearbeiten]
C-Dokumentation für cnd_wait

[bearbeiten] Externe Links

The Old New Thing Artikel: Spurious wake-ups in Win32 condition variables.