notify_one()
/notify_all()
的效果与 wait()
/wait_for()
/wait_until()
的三个原子部分的每一者(解锁+等待、唤醒和锁定)以能看做原子变量修改顺序单独全序发生:顺序对此单独的 condition_variable 是特定的。譬如,这使得 notify_one()
不可能被延迟并解锁正好在进行 notify_one()
调用后开始等待的线程。
通知线程不必保有等待线程所保有的同一互斥上的锁;实际上这么做是劣化,因为被通知线程将立即再次阻塞,等待通知线程释放锁。然而一些实现(尤其是许多 pthread 的实现)辨识此情形,在通知调用中,直接从条件变量队列转移等待线程到互斥队列,而不唤醒它,以避免此“急促并等待”场景。
然而,在要求精确调度事件时,可能必须在处于锁下时通知,例如,在若满足条件则线程将退出程序,导致析构通知线程的 condition_variable 的情况下。互斥解锁之后,但在通知前的虚假唤醒可能导致通知在被销毁对象上调用。
#include <iostream> #include <condition_variable> #include <thread> #include <chrono> 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 == 1\n"; done = true; } void signals() { std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "Notifying falsely...\n"; cv.notify_one(); // 等待线程被通知 i == 0. // cv.wait 唤醒,检查 i ,再回到等待 std::unique_lock<std::mutex> lk(cv_m); i = 1; while (!done) { std::cout << "Notifying true change...\n"; lk.unlock(); cv.notify_one(); // 等待线程被通知 i == 1 , cv.wait 返回 std::this_thread::sleep_for(std::chrono::seconds(1)); lk.lock(); } } int main() { std::thread t1(waits), t2(signals); t1.join(); t2.join(); }
Waiting... Notifying falsely... Notifying true change... ...finished waiting. i == 1