条件变量的虚假唤醒(spurious wakeups)问题
引言
条件变量是我们常用的同步原语之一,它的正确使用方式一般如下图:
在wait端,我们必须把判断布尔条件和wait()放到while循环中,而不能用if语句,原因是可能会引起虚假唤醒。
那么,究竟什么是虚假唤醒,导致虚假唤醒的原因又是什么呢?
什么是虚假唤醒?
举个例子,我们现在有一个生产者-消费者队列和三个线程。
1) 1号线程从队列中获取了一个元素,此时队列变为空。
2) 2号线程也想从队列中获取一个元素,但此时队列为空,2号线程便只能进入阻塞(cond.wait()),等待队列非空。
3) 这时,3号线程将一个元素入队,并调用cond.notify()唤醒条件变量。
4) 处于等待状态的2号线程接收到3号线程的唤醒信号,便准备解除阻塞状态,执行接下来的任务(获取队列中的元素)。
5) 然而可能出现这样的情况:当2号线程准备获得队列的锁,去获取队列中的元素时,此时1号线程刚好执行完之前的元素操作,返回再去请求队列中的元素,1号线程便获得队列的锁,检查到队列非空,就获取到了3号线程刚刚入队的元素,然后释放队列锁。
6) 等到2号线程获得队列锁,判断发现队列仍为空,1号线程“偷走了”这个元素,所以对于2号线程而言,这次唤醒就是“虚假”的,它需要再次等待队列非空。
使用while()判断的原因
在多核处理器下,pthread_cond_signal可能会激活多于一个线程(阻塞在条件变量上的线程)。结果就是,当一个线程调用pthread_cond_signal()后,多个调用pthread_cond_wait()或pthread_cond_timedwait()的线程返回。这种效应就称为“虚假唤醒”。
Linux man page中也有提到:
虚假唤醒造成的后果:
需要对条件进行再判断以避免虚假唤醒:
如果用if判断,多个等待线程在满足if条件时都会被唤醒(虚假的),但实际上条件并不满足,生产者生产出来的消费品已经被第一个线程消费了。
这就是我们使用while去做判断而不是使用if的原因:因为等待在条件变量上的线程被唤醒有可能不是因为条件满足而是由于虚假唤醒。所以,我们需要对条件变量的状态进行不断检查直到其满足条件,不仅要在pthread_cond_wait前检查条件是否成立,在pthread_cond_wait之后也要检查。
参考资料:
http://stackoverflow.com/questions/8594591/why-does-pthread-cond-wait-have-spurious-wakeups
条件变量的虚假唤醒(spurious wakeups)问题相关推荐
- C++11下条件变量之虚假唤醒
概述: 条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制.典型的场景包括生产者-消费者模型,线程池实现等. 对条件变量的使用包括两个动作: 在线程开发的过程中 ...
- 多线程并发编程需要注意虚假唤醒Spurious wakeup
虚假唤醒 Spurious wakeup 如果等待线程在没有通知被调用的情况下唤醒,则称为Spurious wakeup. 解决方案就是: 使用while条件判断,更好的方案是避免使用wait这种低 ...
- [C++11 多线程同步] --- 条件变量的那些坑【条件变量信号丢失和条件变量虚假唤醒(spurious wakeup)】
1 条件变量的信号丢失 1.1 条件变量的信号丢失场景重现 拿生产者和消费者模型举例,看一段示例代码: #include <iostream> #include <vector> ...
- C++条件变量Wait及虚假唤醒
(1) wait(lock): 调用时即阻塞线程,并且调用lock.unlock() (2) wait(lock, conditions): 调用时检查conditions,如果为false,则阻塞线 ...
- linux条件变量唤醒丢失,多线程编程精髓(三)
本篇主要讲Linux环境下的多线程同步内核对象. (1)linux线程同步之互斥体:linux互斥体的用法与windows的临界区对象类似,使用数据结构 pthread_mutex_t表示互斥体对象( ...
- java线程打水问题_Java 多线程 wait() 虚假唤醒问题
本文分享 wait() 的虚假唤醒(Spurious Wakeups)问题,会说明什么是虚假唤醒,以及如何解决. 先看一下相关的 java doc: java doc 说由于中断和虚假唤醒可能会发生 ...
- java suprious wakeup_多线程编程中条件变量和的spurious wakeup 虚假唤醒
1. 概述 条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制.典型的场景包括生产者-消费者模型,线程池实现等. 对条件变量的使用包括两个动作: 1)线程等待某 ...
- linux虚假唤醒(spurious wakeup)
1.Linux对虚假唤醒的说明 On a multi-processor, it may be impossible for an implementation of pthread_cond_sig ...
- c++ linux 线程等待与唤醒_Linux线程同步(互斥量、信号量、条件变量、生产消费者模型)...
为什么要线程同步? 线程间有很多共享资源,都对一个共享数据读写操作,线程操作共享资源的先后顺序不确定,可能会造成数据的冲突 看一个例子 两个线程屏行对全局变量count++ (采用一个val值作为中间 ...
最新文章
- Rclone使用笔记
- 物流系统高可用架构案例
- 外部程序调用Activity的几种方法总结
- asp打印html,asp.net教程之利用ASP在浏览器上打印输出
- 企业融入租时代 谋求轻资产化高效运营
- 两个for还是一个for?
- dedecms自定义表单如何添加发布时间功能
- 拖链电缆 机器人电缆_干货!拖链电缆用途及安装注意事项
- vue中v-for的使用以及注意事项
- Ubuntu12.04中安装ns-allinone-2.34
- android内存溢出案例
- 以汉维语音翻译为例-uniapp原生顶部栏维语翻译-使用字体图标
- PR中我的常用快捷键
- 值得收藏的JavaScript代码
- FPGA基础知识1(FPGA芯片结构)
- python职场应用英语作文_职场英语作文万能句子
- Windows系统的正版与盗版
- vue跨域---解决方案
- HTML、CSS的思维导图
- 删除VSCode 中自定义的snippets
热门文章
- migrate、debate、motivating、agree with、 skin、leather、cease to do、cease doing
- SQL数据库语言基础之SqlServer多表连接查询与INNER JOIN内连接查询
- 有没有一键换天空的修图软件?教你一键修图的简单方法
- BFT-DPoS共识算法讲解
- 循环遍历list集合
- 理解image.shape[:2]与image.shape[:3]
- 医院计算机网络系统作用,计算机网络系统在医院管理中的应用
- 组态王6.53破解下载
- 织梦调用php标签,织梦DEDECMS仿站常用模板调用标签大全
- 功能强大的国产软件,国人却很少知道?