std::condition_variable_any::wait
来自cppreference.com
<tbody>
</tbody>
template< class Lock > void wait( Lock& lock ); |
(1) | (C++11 起) |
template< class Lock, class Predicate > void wait( Lock& lock, Predicate pred ); |
(2) | (C++11 起) |
template< class Lock, class Predicate > bool wait( Lock& lock, std::stop_token stoken, Predicate pred ); |
(3) | (C++20 起) |
wait 导致当前线程阻塞,直至条件变量被通知或发生虚假唤醒。可以提供 pred 以检测虚假唤醒。
1) 原子地调用
lock.unlock(),并在 *this 上阻塞调用线程。 调用线程会在执行 notify_all() 或 notify_one() 时解除阻塞。它也可能因虚假唤醒而解除阻塞。
在解除阻塞时调用
lock.lock()(在锁定时可能还会阻塞),然后返回。2,3) 等待特定条件为真,可用于忽略虚假唤醒。
2) 等价于
while (!pred())wait(lock);
3) 在此调用期间注册
*this,使得在给定的 stoken 的关联停止状态上作出停止请求时提醒它;它等价于while (!stoken.stop_requested()){if (pred())return true;wait(lock);}return pred();
在 wait 返回时,并且调用线程会锁定 lock。如果无法满足此后条件[1],那么就会调用 std::terminate。
- ↑ 重新锁定互斥体的过程中抛出异常就会发生这种情况。
参数
| lock | - | 必须已经由调用线程锁定的锁 |
| stoken | - | 用于注册中断的停止令牌 |
| pred | - | 检查是否可以完成等待的谓词 |
| 类型要求 | ||
-Lock 必须满足可基本锁定 (BasicLockable) 。
| ||
-Predicate 必须满足函数对象 (FunctionObject) 。
| ||
-pred() 必须为合法的表达式,且其类型与值类别必须符合可布尔测试 (BooleanTestable) 要求。
| ||
返回值
1-2) (无)
3) 在返回调用方前
pred() 的最新结果。异常
1) 不抛出
2,3)
pred 抛出的任何异常。注解
重载 (3) 的返回值指示 pred 是否求值为 true,与是否有请求过停止无关。
notify_one()/notify_all() 的效果,与 wait()/wait_for()/wait_until() 的三个原子部分(解锁+等待,唤醒,以及锁定)的每一者,以一个可被看做某个原子变量修改顺序单独全序发生:其顺序特定于这个单独的条件变量。譬如,这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。
示例
运行此代码
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <thread>
std::condition_variable_any cv;
std::mutex cv_m; // 此互斥体用于三个目的:
// 1) 同步对 i 的访问
// 2) 同步对 std::cerr 的访问
// 3) 用于条件变量 cv
int i = 0;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cerr << "等待... \n";
cv.wait(lk, []{return i == 1;});
std::cerr << "...结束等待。i == 1\n";
}
void signals()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(cv_m);
std::cerr << "通知...\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 << "再次通知...\n";
}
cv.notify_all();
}
int main()
{
std::thread t1(waits), t2(waits), t3(waits), t4(signals);
t1.join();
t2.join();
t3.join();
t4.join();
}
可能的输出:
等待...
等待...
等待...
通知...
再次通知...
...结束等待。i == 1
...结束等待。i == 1
...结束等待。i == 1
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
| 缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
|---|---|---|---|
| LWG 2114 (P2167R3) |
C++11 | 到 bool 的可转换性过于弱而无法反映实现的期待
|
加强要求 |
| LWG 2135 | C++11 | 在 lock.lock() 抛出异常时的行为不明确
|
此时会调用 std::terminate |
参阅
| 阻塞当前线程,直到条件变量被唤醒,或到指定时限时长后 (公开成员函数) | |
| 阻塞当前线程,直到条件变量被唤醒,或直到抵达指定时间点 (公开成员函数) | |
cnd_wait 的 C 文档
| |
外部链接
| The Old New Thing 文章: Spurious wake-ups in Win32 condition variables. |