条件变量
类似于pthread
库中的pthread_cond_*()
提供的功能,C++ 11标准提供了两种表示条件变量的类,分别是condition_variable
和condition_variable_any
,定义在头文件<condition_variable>
中
std::condition_variable
当std::condition_variable
对象调用wait()
时,会阻塞当前线程,直到该std::condition_variable
对象被另一线程notify_*()
唤醒
构造函数
- 默认构造
condition_variable()
- 拷贝构造
condition_variable(const condition_variable&)=delete
被禁用,不可拷贝
如下使用条件变量阻塞当前线程
std::mutex mtx;
std::condition_variable cv;
void print(int id) {
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck);
// ...
}
成员函数
std::condition_variable::wait()
重载
- unconditional
在调用void wait(unique_lock<mutex>&);
wait()
前,此时线程应该是加锁状态,因为wait()
在阻塞线程时,会自动调用lck.unlock()
释放锁,使得其他被阻塞在锁竞争上的线程得以执行
当前线程被另一线程notify_*()
唤醒时,则会自动调用lck.lock()
加锁,使得lck
状态和wait()
被调用时相同 - predicate
仅在template<class Predition> void wait(unique_lock<mutex>&, Predition pred);
pred
为false
时,wait()
才会阻塞当前线程
当前线程被另一线程notify_*()
唤醒时,仅在pred
为true
时才会解除阻塞
类似于while(!pred){ wait(lck); }
std::condition_variable::wait_for()
重载
- unconditional
在当前线程被template<class Rep, class Period> cv_status wait_for(unique_lock<std::mutex>&, const chrono::duration<Rep,Period>&)
notify_*()
唤醒前,或在指定时间段内,当前线程会处于阻塞状态 - predicate
仅在template<class Rep, class Period, class Predicate> cv_status wait_for(unique_lock<std::mutex>&, const chrono::duration<Rep,Period>& rel_time, Predicate pred)
pred
为false
时,wait()
才会阻塞当前线程
当前线程被另一线程notify_*()
唤醒时,仅在pred
为true
时才会解除阻塞
类似于return wait_until(lck, chrono::steady_clock::now()+rel_time, std::move(pred));
std::condition_variable::wait_until()
重载
- unconditional
在当前线程被template<class Clock,class Duration> cv_status wait_until(unique_lock<mutex>&,const chrono::time_point<Clock,Duration>&)
notify_*()
唤醒前,或在指定时间点前,当前线程会处于阻塞状态 - predicate
仅在template<class Clock, class Duration, class Predicate> cv_status wait_until(unique_lock<mutex>&, const chrono::time_point<Clock,Duration>& abs_time, Predicate pred)
pred
为false
时,wait()
才会阻塞当前线程
当前线程被另一线程notify_*()
唤醒时,仅在pred
为true
时才会解除阻塞
类似于while(!pred){ if(wait_until(lck,abs_time)==cv_status::timeout){ return pred; } } return true;
-
std::condition_variable::notify_one()
唤醒某个等待wait线程,若有多个等待线程,则唤醒的线程是不确定的 -
std::condition_variable::notify_all()
唤醒所有等待wait线程
std::condition_variable_any
与std::condition_variable
不同的是,std::condition_variable_any
的wait()
可以接收任何lockable参数,如递归互斥锁、定时互斥锁等
而std::condition_variable
的wait()
仅可以接收std::unique_lock<std::mutex>
类型
std::cv_status枚举类型
cv_status::no_timeout
wait_for()
或wait_until()
未超时,即在规定时间段内线程收到notify_*()
通知cv_status::timeout
wait_for()
或wait_until()
超时
辅助函数
std::notify_all_at_thread_exit()
函数原型
void std::notify_all_at_thread_exit(condition_variable& cond,unique_lock<std::mutex>);
当调用该函数的线程退出时,所有在cond
条件变量上等待的线程都会收到通知
示例如下:
#include <iostream>
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable_any
std::mutex mtx;
std::condition_variable_any cv;
bool ready= false;
void print_id(int id) {
std::unique_lock<std::mutex> lck(mtx);
while(!ready){
cv.wait(lck);
}
std::cout << "thread id:" << id << std::endl;
}
void go() {
std::unique_lock<std::mutex> lck(mtx);
std::notify_all_at_thread_exit(cv, std::move(lck));
ready= true;
}
int main() {
std::thread threads[10];
for (int i = 0; i < 10; ++i){
threads[i] = std::thread(print_id, i);
}
std::cout<< "10 threads ready to race..."<<std::endl;
std::thread(go).detach();
for (auto& th : threads) {
th.join();
}
return 0;
}