std::condition_variable_any::notify_one
来自cppreference.com
<tbody>
</tbody>
void notify_one() noexcept; |
(C++11 起) | |
若有任何线程在 *this 上等待,则调用 notify_one 会解除其中一个阻塞的线程。
参数
(无)
返回值
(无)
注解
notify_one()/notify_all() 的效果,与 wait()/wait_for()/wait_until() 的三个原子部分(解锁+等待,唤醒,以及锁定)的每一者,以一个可被看做某个原子变量修改顺序单独全序发生:其顺序特定于这个单独的条件变量。譬如,这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。
通知线程不必保有与等待线程所保有的同一互斥体上的锁;实际上这么做会劣化,因为被通知线程将立即再次阻塞,以等待通知线程释放锁。然而一些实现(尤其是许多 pthread 的实现)会辨识这种情形,在通知调用中将等待线程直接从条件变量的队列转移到互斥体的队列而不唤醒它,以避免这种“急促唤醒再等待”的场景。
然而无论如何,在要求精确调度事件时,可能必须在处于锁定时进行通知,例如,若等待线程在满足条件时将会退出程序,导致通知线程的条件变量被析构的情况下。互斥体解锁之后,但在通知前的虚假唤醒可能导致在已销毁对象上调用通知。
示例
运行此代码
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <thread>
using namespace std::chrono_literals;
std::condition_variable_any cv;
std::mutex cv_m;
int i = 0;
bool done = false;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cout << "等待... \n";
cv.wait(lk, []{ return i == 1; });
std::cout << "...结束等待; i == " << i << '\n';
done = true;
}
void signals()
{
std::this_thread::sleep_for(200ms);
std::cout << "假通知...\n";
cv.notify_one(); // 等待线程被通知且 i == 0。
// cv.wait 被唤醒,检查 i,再回到等待
std::unique_lock<std::mutex> lk(cv_m);
i = 1;
while (!done)
{
std::cout << "真的改动通知...\n";
lk.unlock();
cv.notify_one(); // 等待线程被通知且 i == 1,cv.wait 返回
std::this_thread::sleep_for(300ms);
lk.lock();
}
}
int main()
{
std::thread t1(waits), t2(signals);
t1.join();
t2.join();
}
可能的输出:
等待...
假通知...
真的改动通知...
...结束等待; i == 1
参阅
| 通知所有等待的线程 (公开成员函数) | |
cnd_signal 的 C 文档
| |