std::condition_variable:: notify_one
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Member functions | ||||
| Notification | ||||
|
condition_variable::notify_one
|
||||
| Waiting | ||||
| Native handle | ||||
|
void
notify_one
(
)
noexcept
;
|
(seit C++11) | |
Falls Threads auf
*
this
warten, hebt der Aufruf von
notify_one
einen der wartenden Threads auf.
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
Modifikationsreihenfolge
einer atomaren Variable betrachtet werden kann: Die Reihenfolge ist spezifisch für diese individuelle Condition Variable. Dies macht es unmöglich, dass
notify_one()
beispielsweise verzögert wird und einen Thread entsperrt, der gerade nach dem Aufruf von
notify_one()
mit dem Warten begonnen hat.
Der benachrichtigende Thread muss die Sperre nicht auf demselben Mutex halten wie der/die wartenden Thread(s); Tatsächlich ist dies eine Pessimierung, da der benachrichtigte Thread sofort wieder blockieren würde, während er darauf wartet, dass der benachrichtigende Thread die Sperre freigibt. Einige Implementierungen (insbesondere viele Implementierungen von pthreads) erkennen jedoch diese Situation und vermeiden dieses "Hurry up and wait"-Szenario, indem sie den wartenden Thread während des Notify-Aufrufs direkt von der Warteschlange der Condition Variable in die Warteschlange des Mutex transferieren, ohne ihn aufzuwecken.
Das Benachrichtigen unter Sperre kann dennoch notwendig sein, wenn eine präzise Planung von Ereignissen erforderlich ist, z.B. wenn der wartende Thread das Programm beenden würde, falls die Bedingung erfüllt ist, was zur Zerstörung der Condition Variable des benachrichtigenden Threads führt. Ein falsches Aufwachen nach dem Entsperren des Mutex, aber vor der Benachrichtigung, würde dazu führen, dass die Benachrichtigung auf einem zerstörten Objekt aufgerufen wird.
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
Siehe auch
|
benachrichtigt alle wartenden Threads
(öffentliche Mitgliedsfunktion) |
|
|
C-Dokumentation
für
cnd_signal
|
|