变量使用详解 wait"/>
c++ 条件变量使用详解 wait
c++ 条件变量使用详解
std::condition_variable
- 线程间同步的条件变量类。允许一个或多个线程在满足特定条件之前等待,同时允许其他线程通知、唤醒等待的线程。
成员函数
notify_one
:通知一个等待的线程。notify_all
:通知所有等待的线程。wait
:阻塞当前线程,直到条件变量被唤醒。wait_until
:阻塞当前线程,直到条件变量被唤醒,或直到抵达指定时间点。wait_for
:阻塞当前线程,直到条件变量被唤醒,或直到指定时限时长后。
使用方法
- 对于修改条件后通知其他线程的线程:
- 获得 std::mutex,通常使用 std::lock_guard;
- 在成功获得锁后,修改条件;
- 使用 notify_one 或 notify_all 唤醒等待的线程;
- 对于等待唤醒的线程:
- 获得 std::mutex,通常使用 std::unique_lock;
- 使用 wait,wait_for,wait_until 等待唤醒,此时线程释放互斥,并进入阻塞;
- 被其他线程唤醒,被虚假唤醒或者等待超时,线程自动重获得互斥,此时应检查条件是否成立,若不成立,则继续等待或者返回;
虚假唤醒
- 指线程在等待期间,重新获得互斥,而这一行为却不来源于其他任何线程的通知,则称之为虚假唤醒。
- 按照 c++ 标准规定,虚假唤醒出现的数量以及比率都不确定。
notify_one notify_all
- 使用注意:在唤醒其他线程时,通知线程一般无需持有互斥,因为被唤醒线程醒来后,一旦不能立即获得互斥,将会再次阻塞。
wait
-
函数原型:
void wait(std::unique_lock<std::mutex>& lock); // 若发生虚假唤醒,wait 之后的代码将会被执行template<class Predicate> void wait(std::unique_lock<std::mutex>& lock, Predicate pred); // 相当于 while (!pred()) {wait(lock); } // 可以避免虚假唤醒
lock
:互斥体,必须被当前线程锁定;pred
:返回 false,则继续等待。其签名为bool pred()
;
-
使当前线程阻塞直至条件变量被通知,或虚假唤醒发生,可选地循环直至满足 pred。
wait_until
-
函数原型:
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::timeouttemplate<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()) {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。
-
使用注意:时钟最好使用稳定时钟,即计时速率恒定且无法调整的时钟。
wait_for
-
函数原型:
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::timeouttemplate<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 <iostream> #include <condition_variable> #include <thread> #include <chrono>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; }
更多推荐
c++ 条件变量使用详解 wait
发布评论