多线程编程中条件变量和虚假唤醒的讨论
1. 概述
条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制。典型的场景包括生产者-消费者模型,线程池实现等。
对条件变量的使用包括两个动作:
1) 线程等待某个条件, 条件为真则继续执行,条件为假则将自己挂起(避免busy wait,节省CPU资源);
2) 线程执行某些处理之后,条件成立;则通知等待该条件的线程继续执行。
3) 为了防止race-condition,条件变量总是和互斥锁变量mutex结合在一起使用。
一般的编程模式:
var mutex;
var cond;
var something;
Thread1: (等待线程)
lock(mutex);
while( something not true ){
condition_wait( cond, mutex);
}
do(something);
unlock(mutex);
//============================
Thread2: (解锁线程)
do(something);
....
something = true;
unlock(mutex);
condition_signal(cond);
函数说明:
(1) Condition_wait():调用时当前线程立即进入睡眠状态,同时互斥变量mutex解锁(这两步操作是原子的,不可分割),以便其它线程能进入临界区修改变量。
(2) Condition_signal(): 线程调用此函数后,除了当前线程继续往下执行以外; 操作系统同时做如下动作:从condition_wait()中进入睡眠的线程中选一个线程唤醒, 同时被唤醒的线程试图锁(lock)住互斥量mutex, 当成功锁住后,线程就从condition_wait()中成功返回了。
2. 函数接口
pthread: pthread_cond_wait/pthread_cond_signal/pthread_cond_broadcast()
Java: Condition.await()/Condition.signal()/Condition.signalAll()
3. 虚假唤醒(spurious wakeup)在采用条件等待时,我们使用的是
while(条件不满足){
condition_wait(cond, mutex);
}
而不是:
If( 条件不满足 ){
Condition_wait(cond,mutex);
}
这是因为可能会存在虚假唤醒”spurious wakeup”的情况。
也就是说,即使没有线程调用condition_signal, 原先调用condition_wait的函数也可能会返回。此时线程被唤醒了,但是条件并不满足,这个时候如果不对条件进行检查而往下执行,就可能会导致后续的处理出现错误。
虚假唤醒在linux的多处理器系统中/在程序接收到信号时可能回发生。在Windows系统和JAVA虚拟机上也存在。在系统设计时应该可以避免虚假唤醒,但是这会影响条件变量的执行效率,而既然通过while循环就能避免虚假唤醒造成的错误,因此程序的逻辑就变成了while循环的情况。
注意:即使是虚假唤醒的情况,线程也是在成功锁住mutex后才能从condition_wait()中返回。即使存在多个线程被虚假唤醒,但是也只能是一个线程一个线程的顺序执行,也即:lock(mutex) 检查/处理 condition_wai()或者unlock(mutex)来解锁.
4. 解锁和等待转移(wait morphing)
解锁互斥量mutex和发出唤醒信号condition_signal是两个单独的操作,那么就存在一个顺序的问题。谁先随后可能会产生不同的结果。如下:
[color=red](1) 按照 unlock(mutex); condition_signal()顺序, 当等待的线程被唤醒时,因为mutex已经解锁,因此被唤醒的线程很容易就锁住了mutex然后从conditon_wait()中返回了。
//...
unlock(mutex);
condition_signal(cond);
(2) 按照 condition_signal(); unlock(mutext)顺序,当等待线程被唤醒时,它试图锁住mutex,但是如果此时mutex还未解锁,则线程又进入睡眠,mutex成功解锁后,此线程在再次被唤醒并锁住mutex,从而从condition_wait()中返回。
//...
condition_signal(cond);
unlock(mutex);
[/color]
可以看到,按照(2)的顺序,对等待线程可能会发生2次的上下文切换,严重影响性能。因此在后来的实现中,对(2)的情况,如果线程被唤醒但是不能锁住mutex,则线程被转移(morphing)到互斥量mutex的等待队列中,避免了上下文的切换造成的开销。 --
wait morphing
编程时,
推荐采用(1)的顺序解锁和发唤醒信号。
而Java编程只能按照(2)的顺序,否则发生异常!!。
在SUSv3
http://en.wikipedia.org/wiki/Single_UNIX_Specification的规范中(pthread),指明了这两种顺序不管采用哪种,其实现效果都是一样的。
分享到:
相关推荐
Understanding-Spurious-Free-Dynamic-Range-in-Wideband-GSPS-ADCs
虚假的Spurious是一个工具集,允许在本地对一部分AWS资源进行开发。 这些服务作为Docker容器运行,Spurious管理它们的生命周期和链接,因此您只需要担心使用这些服务。 要使用Spurious,您需要将每个AWS服务的终结点...
杂散发射Spurious与带外发射的区别.pdf杂散发射Spurious与带外发射的区别.pdf杂散发射Spurious与带外发射的区别.pdf杂散发射Spurious与带外发射的区别.pdf杂散发射Spurious与带外发射的区别.pdf
AT91SAM7S64的中文手册特点 • 集成了ARM7TDMI® ARM® ...– 两个外部中断源和一个快速中断源,可以防止虚假(spurious)中断 • 调试单元(DBGU) – 2线UART,支持调试通讯通道中断;可通过程序来禁止通过ICE进行访问
虚假相关 通过使用非参数检验来评估显着性,避免测量与幂律动态之间的虚假相关性...N Schaworonkow、DAJ Blythe、J Kegeles、G Curio、VV Nikulin:神经元和行为数据中的幂律动力学引入了虚假相关性。 人脑映射。 2015.
# Spurious Clojure AWS SDK Helper 受原始启发:它将 AWS 开发工具包配置为使用 (Spurious 是一个工具集,允许在本地针对 AWS 资源的子集进行开发)。 用法 您可以在标准 Clojure 应用程序中或通过在容器中运行的...
信息安全_数据安全_us-18-Mulasmajic-Peterson-Why-So-Spurious 安全威胁 威胁情报 业务风控 系统安全 安全体系
虚假的 为什么这么假? 因为有时候真实的东西太冒险了。 databaseSaver.save() // real records, yikes! requestMaker.makeRequest() // pound that server! rainMaker.makeRain() // goodness no! Spurious使测试...
Spurious-free dynamic range (SFDR) limited by intermodulation distortions is a usually accepted measure for dynamic performance of a photonic time-stretched analog-to-digital converter (ADC)....
Reconstruction of Complex Networks Under Missing and Spurious Noise Without Prior Knowledge
http://www.wholetomato.com/binaries/VA_X_Setup1640.exe<br><br>这个版本已经是正式版了,稳定性没的说,中文的问题已经得到了很好的解决,已经可以正常显示了,只是包含有中文的注释,在va outline中显示为...
本文主要讨论的是超短波接收机大动态范围的概念和相关参数的测试方法。 噪声系数(NF)、灵敏度(Sensitivity)、双音互调失真(Two-tone intermodulation distortion)、三阶截点(Third-order intercept point,)...
数据集格式:Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件,仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数):693 标注数量(xml文件个数):693 标注类别数:6 标注类别名称:["missing_hole",...
Missing_hole 、Mouse_bite、Open_circuit、Short、Spur、Spurious_copper六个文件夹,每个文件夹下分为images和labels两个目录,存放图片和对应的xml标签 除此之外,提供了可视化的脚本,展示后保存在当前目录下 ...
虚假的如果您想使用这个 gem 来伪造与 S3 的交互,您可能需要查看 ,它支持包含在 CLI 工具中的其他虚假 AWS 服务。安装克隆这个 repo 并运行: docker build -t <yourname>/spurious-s3 . ,这应该构建在 Docker 中...
阅读的安装说明,因为浏览器是由spurious 启动和运行的服务之一。 贡献 分叉它( ) 创建您的功能分支( git checkout -b my-new-feature ) 提交您的更改( git commit -am 'Add some feature' ) 推送到分支( ...
Its a document for Spurious power suppression technique
approaches can give spurious solutions, however. The idea behind this article is to reduce the number of spurious solutions by combining basic and readily available information about the connectivity ...
The proposed architecture achieves a high compression ratio with a spurious response comparable to that of recent ROM compression techniques. To validate the proposed DDS architecture, the linear, ...