C++多线程:condition_variable
条件变量
类似于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;
}

浙公网安备 33010602011771号