notify_one
:通知一个等待的线程。notify_all
:通知所有等待的线程。wait
:阻塞当前线程,直到条件变量被唤醒。wait_until
:阻塞当前线程,直到条件变量被唤醒,或直到抵达指定时间点。wait_for
:阻塞当前线程,直到条件变量被唤醒,或直到指定时限时长后。函数原型:
void wait(std::unique_lock<std::mutex>& lock);
// 若发生虚假唤醒,wait 之后的代码将会被执行
template<class Predicate>
void wait(std::unique_lock<std::mutex>& lock, Predicate pred);
/** 相当于
while (!pred()) {
通过检查 pred 返回值,可以避免虚假唤醒
wait(lock);
}
**/
lock
:互斥体,必须被当前线程锁定;pred
:返回 false,则继续等待。其签名为 bool pred()
;使当前线程阻塞直至条件变量被通知,或虚假唤醒发生,可选地循环直至满足 pred。
函数原型:
template<class Clock, class Duration>
std::cv_status wait_until(std::unique_lock<std::mutex>& lock,
const std::chrono::time_point<Clock, Duration>& timeout_time);
// 被其他线程唤醒或发生虚假唤醒,未超时,返回 std::cv_status::no_timeout
// 超时则返回 std::cv_status::timeout
template<class Clock, class Duration, class Pred>
bool wait_until(std::unique_lock<std::mutex>& lock,
const std::chrono::time_point<Clock, Duration>& timeout_time,
Pred pred);
/** 相当于
while (!pred()) {
通过检查 pred 返回值,可以避免虚假唤醒
if (wait_until(lock, timeout_time) == std::cv_status::timeout) {
return pred();
}
}
return true;
**/
lock
:互斥体,必须被当前线程锁定;timeout_time
:表示停止等待时间的 std::chrono::time_point 类型对象;pred
:返回 false,则继续等待。其签名为 bool pred()
;使当前线程阻塞直至条件变量被通知、抵达指定时间或虚假唤醒发生,可选的循环直至满足 pred。
使用注意:时钟最好使用稳定时钟,即计时速率恒定且无法调整的时钟。
函数原型:
template<class Rep, class Period>
std::cv_status wait_for(std::unique_lock<std::mutex>& lock,
const std::chrono::duration<Rep, Period>& rel_time);
// 被其他线程唤醒或发生虚假唤醒,未超时,返回 std::cv_status::no_timeout,
// 超时则返回 std::cv_status::timeout
template<class Rep, class Period, class Predicate>
bool wait_for(std::unique_lock<std::mutex>& lock,
const std::chrono::duration<Rep, Period>& rel_time,
Predicate pred);
// 相当于
// wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(pred));
lock
:互斥体,必须被当前线程锁定;rel_time
:表示等待所耗的最大时间的 std::chrono::duration 类型对象。rel_time 必须足够小,以在加到 std::chrono::steady_clock::now() 时不溢出;pred
:返回 false,则继续等待。其签名为 bool pred()
;使当前线程阻塞直至条件变量被通知、抵达指定时间或虚假唤醒发生,可选的循环直至满足 pred。
由于操作系统调度或资源争议,此函数可能阻塞长于 rel_time。
线程1修改变量,线程2等待变量被修改。
#include
#include
#include
#include
using namespace std::chrono_literals;
int i = 0;
bool changed{false};
std::condition_variable cv;
std::mutex cv_m;
void wait()
{
std::unique_lock<std::mutex> lk(cv_m);
// std::chrono_literals::100ms, c++14 引入
if (cv.wait_for(lk, 100ms, [](){return changed;})) {
printf("finished waiting, i is %d\n", i);
} else {
printf("wait timeout, i is %d\n", i);
}
}
void notify()
{
{
std::this_thread::sleep_for(50ms);
std::lock_guard<std::mutex> lk(cv_m);
i = 10;
changed = true;
printf("change finished\n");
}
cv.notify_one();
}
int main()
{
std::thread t1(notify);
std::thread t2(wait);
t1.join();
t2.join();
return 0;
}