std::condition_variable::notify_one
| void notify_one() noexcept; |
(seit C++11) | |
Wenn Threads auf *this warten, hebt die Aufrufung von notify_one die Blockierung eines der wartenden Threads auf.
Inhalt |
[bearbeiten] Parameter
(keine)
[bearbeiten] Rückgabewert
(keine)
[bearbeiten] Hinweise
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.
Der benachrichtigende Thread muss die Sperre auf demselben Mutex nicht halten wie der oder die wartenden Threads; tatsächlich ist dies eine Pessimierung, da der benachrichtigte Thread sofort wieder blockiert würde und darauf wartet, dass der benachrichtigende Thread die Sperre freigibt. Einige Implementierungen (insbesondere viele Implementierungen von pthreads) erkennen diese Situation jedoch und vermeiden dieses "schnell-und-warte"-Szenario, indem sie den wartenden Thread während des Aufrufs von notify von der Warteschlange der Condition Variable direkt in die Warteschlange des Mutex verschieben, ohne ihn aufzuwecken.
Eine Benachrichtigung unter Sperre kann dennoch erforderlich sein, wenn eine präzise Zeitplanung von Ereignissen erforderlich ist, z. B. wenn der wartende Thread das Programm beenden würde, wenn die Bedingung erfüllt ist, was zur Zerstörung der Condition Variable des benachrichtigenden Threads führen würde. Ein spurious wakeup nach dem Entsperren des Mutex, aber vor dem notify, würde dazu führen, dass notify auf einem zerstörten Objekt aufgerufen wird.
[bearbeiten] Beispiel
#include <chrono> #include <condition_variable> #include <iostream> #include <thread> using namespace std::chrono_literals; std::condition_variable cv; std::mutex cv_m; int i = 0; bool done = false; void waits() { std::unique_lock<std::mutex> lk(cv_m); std::cout << "Waiting... \n"; cv.wait(lk, []{ return i == 1; }); std::cout << "...finished waiting; i == " << i << '\n'; done = true; } void signals() { std::this_thread::sleep_for(200ms); std::cout << "Notifying falsely...\n"; cv.notify_one(); // waiting thread is notified with i == 0. // cv.wait wakes up, checks i, and goes back to waiting std::unique_lock<std::mutex> lk(cv_m); i = 1; while (!done) { std::cout << "Notifying true change...\n"; lk.unlock(); cv.notify_one(); // waiting thread is notified with i == 1, cv.wait returns std::this_thread::sleep_for(300ms); lk.lock(); } } int main() { std::thread t1(waits), t2(signals); t1.join(); t2.join(); }
Mögliche Ausgabe
Waiting... Notifying falsely... Notifying true change... ...finished waiting; i == 1
[bearbeiten] Siehe auch
| benachrichtigt alle wartenden Threads (public member function) | |
| C-Dokumentation für cnd_signal
| |