c/c++条件变量的使用注意要点
正文
多线程下使用条件变量需要注意一些要点
- 1.消费者线程尽量使用time_wait,去定期检查消费者队列长度,这可以防止一些notify丢失的问题而导致的消费者block,譬如说在cpu调度上:
如果先进行了notify,然后此时消费者线程才开始运行执行了wait,此时notify是消失的,消费者线程将会永远阻塞, 一个常见的错误程序如下,看上去正确的程序由于无法保证thread能够中的wait能够先运行,可能在wait的时候fn还Block在unique_lock下, notify()的时候还没有执行到wait()导致子线程永远阻塞到wait()上。(条件变量和信号量是有区别的,条件变量的notify实质是发送一个信号,并不具有++的持久性)
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex m;
std::condition_variable cv;
void fn(){
std::cout<<"fn start\n";
std::unique_lock<std::mutex> lck(m);
cv.wait(lck);
std::cout<<"fn finish\n";
}
int main()
{
std::thread worker(fn);
{
std::cout<<"sleep start\n";
std::lock_guard<std::mutex> lck(m);
std::cout<<"notify start\n";
cv.notify_one();
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout<<"sleep finish\n";
}
std::cout<<"lock free\n";
worker.join();
return 0;
}
notify丢失的问题,涉及到异步线程无法保证时序性的情况下,最好的处理方式是使用超时检测,去判断是否已经处于结束状态,c++中提供了wait_for, 一个伪代码示例
std::condition_variable cv;
std::mutex m;
void fn(){
while(1){
std::unique_lock<std::mutex> lk(cv_m);
cv.wait_for(lk, 100ms);
if(quit){
return;
}
//do..task
}
}
- 2.消费者线程wait调用结束时外层一定要使用while循环去校验消费者队列情况,因为存在一些虚假唤醒,以及一些惊群唤醒的情况, 避免接下来的消费逻辑处理出现异常
std::unique_lock<std::mutex> lck(m);
while(queue.len() == 0){
cv.wait(lck);
}
-
3.尽量用notify_one去避免多线程惊群效应
-
4.notify时要放在lock外面,notify的本质是发送一个信号告知消费者线程,其接收到信号后就会去lock对应的mutex,如果此时mutex获取不到,就白白的浪费了一次调度(拿不到锁陷入阻塞,直到后续消费者线程释放锁了之后才拿到)
-
5.现代c++的写法
c++11之后支持如下写法:
template< class Predicate >
void wait( std::unique_lock<std::mutex>& lock, Predicate stop_waiting );
等价于
while (!stop_waiting())
{
wait(lock);
}
所以就可以这么写了
std::unique_lock<std::mutex> lock(mutex);
hasFrame.wait(lock, [this]() { return !FrameList.empty() || _quit; });
AVFramePtr ret = _avFrameList.front();
ref
1.用条件变量实现事件等待器的正确与错误做法--陈硕,https://www.cnblogs.com/Solstice/p/3309089.html#3035115
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
2020-01-14 webrtc源码分析-信号槽实现