当前位置: 首页 > news >正文

计算机原理—条件变量为什么会有假唤醒

一、条件变量

在多线程的实际开发中,经常会用到条件变量。而使用条件变量时,比如标准库或Posix中的Conditional都会使用类似下面的代码来实现:

while(!pred())wait(lock);

很多开发者特别是初学者,往往不明白为什么要增加一个while循环处理。后面用得多了接触广了,也只是听说可能是因为系统底层会出现信号误发射导致的条件变量的假唤醒。但一般大多数开发者也到此不再追根究底了。但为什么系统会误发信号呢?

二、假唤醒

spurious wakeup,假唤醒。很好理解,没想唤醒可却唤醒了,即这种唤醒不是开发者设计的或希望的(这和前面的伪共享有点类似)。条件变量监控的就是触发的信号,而这个信号是无论是谁触发,都需要经过系统的中转。而系统如果未经触发或别的信号的触发却进行了中转发射,就会产生假唤醒。
当然,还有其它的情况的假唤醒,比如多线程竞态导致的线程间竞争引入的假唤醒等。所以下面将对假唤醒的底层机制进行分析和说明。

三、原因

假唤醒的原因有很多种情况,一般主要的来说,分为系统层级和应用层级两种原因。下面将分别进行说明,重点分析说明一下系统层次的应用。
A.应用层级
应用层级的产生原因,主要在于多个线程等待时,如果捕获信号的机制有问题会导致错误的触发本应该无法被触发的线程,从而产生假唤醒。但这种问题,更多的是逻辑处理问题,并不是假唤醒的根本原因(理论上惊群也算)。
B.系统层次
系统层的主要原因也分为几类:

  1. 真实唤醒
    这种真实唤醒是基于底层的信号真正发射导致的正常唤醒,但因为条件变量内部的安全机制导致被唤醒的线程无法进行工作,这有点类似于“惊群”。这也是条件变量内部实现的问题,它是正常的。
  2. 多核和多CPU的竞态
    在这种情况下,signal发出信号导致多个线程被唤醒,这和原因1中的内容有呼应的意思
  3. 信号中断
    在前面分析过,条件变量一般是基于futex等系统调用,如果收到信号(如SIGINT),阻塞的系统调用可能被中断返回EINTR,而wait内部机制都会处理这个EINTR,导致线程的假唤醒。
  4. 内核调度
    在多核处理器上,现代操作系统存在着多线程调度、指令重排序或缓存一致性协议等复杂的应用,在某些特殊的场景下也可能导致假唤醒。另外,调度器的策略也有可能在某些情况下为避免死锁等情况唤醒一些低优先级的线程

四、假唤醒的应对

假唤醒的处理其实从根本上解决并不难,但为什么要丢给上层的开发者呢?说白了就是成本。底层如果使用更大粒度的锁就会解决这个问题,但导致的结果就是性能的急剧下降。投入和产出严重不成正比。所以在上层应用的标准(如POSIX等)都允许假唤醒的存在。既然交给了应用者,怎么解决这个问题呢?有两种方法,基本类似:

  1. while循环机制
    这种方法与开头的方式一样:
    //使用 while+bool变量进行std::unique_lock<std::mutex>lock(mtx);while(!condition){cv.wait(lock);}
  2. 引入wait中的谓词
    std::unique_lock<std::mutex>lock(mtx);// 使用谓词来避免虚假唤醒cv.wait(lock,[]{returnready;});

注意,上面的两种情况是等价的。即虽然谓词情况下没有循环,但实际实现了类似的功能。

五、总结

对问题追根究底,从技术层面一定是好事。但在工程项目中就要从整体考虑了,不能因噎废食。但总体的原则还是要把握,不能学“上大人孔乙己”的四种“茴”字的写法那种学习方式。

http://www.jsqmd.com/news/505913/

相关文章:

  • SA8155开发板实战:用ADB和BusyBox快速搭建QNX Shell调试环境
  • 别再死记HashMap了!多线程死循环、数据丢失,这些坑90%的人都踩过
  • 三万亩樱桃花开,九洞天邀全民拍春——短视频大赛启动
  • 数学建模实战:从K-means到DBSCAN的聚类算法全解析
  • YOLOv12镜像优化升级:支持TensorRT导出,边缘部署更便捷
  • HDR与SDR核心转换:Gamma、HLG、PQ的视觉模型与参数设计解析
  • OpenClaw如何配置以及相关的开源AI项目汇总大全(2026最新版)
  • MySQL基础操作清单
  • 记不住 Linux 命令?我写了个终端,点一下就行
  • 深度学习性能优化:GFLOPS与GPU选型实战指南
  • 《认知流形上的场方程及其在碳硅关系中的应用》(沙地实验)
  • 让数据说话:运营场景下高效产出专业图表工具推荐
  • MQ-6丙烷传感器在GD32E230上的ADC+DMA采集实现
  • 京东E卡回收攻略,教你如何快速兑换现金! - 团团收购物卡回收
  • 2026年3月,3公里内宠物医院哪家强?来评测 - 品牌推荐师
  • 手把手教你用Spiffo开发板搭建最小Linux系统(附全志H618避坑指南)
  • 效果对比:Qwen-Image-Edit-F2P在不同算力GPU下的生成速度与质量评测
  • 3分钟搭建专属Java在线编译器:零配置开发环境终极指南
  • FreeRTOS多任务调度下的温湿度监测系统设计
  • 国际航空货运合规之选,深圳聚鑫印刷涂炭空运单印刷专业靠谱 - 博客万
  • Dify平台集成CasRel模型实战:快速构建智能关系抽取应用
  • GitHub全界面中文化解决方案:突破语言障碍的开发效率提升指南
  • 3MF技术格式:重塑3D打印工作流的开源工具解决方案
  • 含风光储荷微电网多目标优化系统代码功能说明
  • AMS1117-3.3V稳压器是什么?有哪些应用
  • JeecgBoot低代码 AI工作流循环节点:批量处理与迭代控制的利器
  • PX4与Gazebo协同实现多无人机动态编队仿真实践
  • Ansys HFSS同轴电缆仿真全流程:从建模到结果分析(附参数设置)
  • Sentinel 注解支持:@SentinelResource 高级用法
  • Langchain架构解析:从文本到向量再到答案的完整流程详解