关于pthread_cond_wait使用while循环判断的理解
在Stevens的《Unix 环境高级编程》中第11章线程关于pthread_cond_wait的介绍中有一个生产者-消费者的例子P311,
在进入pthread_cond_wait前使用while进行条件判断,而没有直接使用if,耐人费解!
代码如下: #include <pthread.h>
struct msg {
struct msg *m_next;
/* value...*/
}; struct msg* workq;
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER; void
process_msg() {
struct msg* mp;
for (;;) {
pthread_mutex_lock(&qlock);
while (workq == NULL) {
pthread_cond_wait(&qread, &qlock);
}
mq = workq;
workq = mp->m_next;
pthread_mutex_unlock(&qlock);
/* now process the message mp */
}
} void
enqueue_msg(struct msg* mp) {
pthread_mutex_lock(&qlock);
mp->m_next = workq;
workq = mp;
pthread_mutex_unlock(&qlock);
/** 此时另外一个线程在signal之前,执行了process_msg,刚好把mp元素拿走*/
pthread_cond_signal(&qready);
/** 此时执行signal, 在pthread_cond_wait等待的线程被唤醒,
但是mp元素已经被另外一个线程拿走,所以,workq还是NULL ,因此需要继续等待*/
} 这里process_msg相当于消费者,enqueue_msg相当于生产者,struct msg* workq作为缓冲队列
解释如下
在process_msg中使用while(workq==NULL)循环判断条件,这里主要是因为在enqueue_msg中unlock之后才唤醒等待
的线程,会出现上述注释出现的情况,造成workq==NULL,因此需要继续等待。
但是如果将pthread_cond_signal移到pthread_mutex_unlock()之前执行,则会避免这种竞争,在unlock
之后,会首先唤醒pthread_cond_wait的线程,进而workq!=NULL总是成立。
pthread_cond_wait返回时无法保证判断式是真是假,因此需要重新判断。因此建议使用while循环进行验证,以便能够容忍这种竞争。
http://yaronspace.cn/blog/archives/1479
还有一种解释如下所示
http://bbs.csdn.net/topics/370094313
我猜应该是这个意思:
假设有两个线程(我就用伪代码了):
//thread 1
while(0<x<10)
pthread_cond_wait(); //thread 2
while(5<x<15)
pthread_cond_wait(); 如果某段时间内 x == 8,那么两个线程相继进入等待。 然后,另一个线程3:
修改x:x = 12
if(..) phtread_cond_signal() 那么,虽然线程1、2都被唤醒了,但是,此时线程1仍然不满足while,只有线程1跳出while,
我们假设一种情况线程2线获得了锁,然后发现满足循环条件,之后又有执行pthread_cond_wait()函数,然后阻塞在这儿,并且释放锁!
,pthread_cond_signal在多处理器上可能同时唤醒多个线程,当你只能让一个线程处理某个任务时,其它被唤醒的线程就需要继续wait,while循环的意义就体现在这里了,而且规范要求pt hread_cond_signal至少唤醒一个pthread_cond_wait上的线程,其实有些实现为了简单在单处理器上也会唤醒多个线程.
,某些应用,如线程池,pthread_cond_broadcast唤醒全部线程,但我们通常只需要一部分线程去做执行任务,所以其它的线程需要继续wait.所以强烈推荐此处使用while循环.
其实说白了很简单,就是pthread_cond_signal()也可能唤醒多个线程,而如果你同时只允许一个线程访问的话,就必须要使用while来进行条件判断,以保证临界区内只有一个线程在处理
关于pthread_cond_wait使用while循环判断的理解的更多相关文章
- Python条件循环判断
1.条件判断语句 Python中条件选择语句的关键字为:if .elif .else这三个.其基本形式如下: 1 2 3 4 5 6 7 8 9 age_of_cc = 27 age = int( ...
- PHP循环语句深度理解分析——while, for, foreach, do while
循环结构 一.while循环 while(表达式) { 循环体;//反复执行,直到表达式为假 } 代码: $index = 1; while ($index<5) { ...
- jquery for循环判断是否重复
//使用for循环 判断是否有重名 var len=$("li").length;//获取页面中所有li的数量 for(var i=0; i<len; i++){ oldna ...
- R语言学习——循环判断语句
循环 判断 函数 函数是一个对象,可以赋值 函数要放在调用函数的前面 输入输出 read.csv()------文本文件 csv是comma separated value的英文缩写,其读取逗号分隔 ...
- if循环判断
if循环判断 if-else循环的语法格式 if 逻辑判断句: 代码块 # 缩进表示所属关系 else 逻辑判断句: 代码块 if 和elif同时使用来做多层判断 if 逻辑判断式: 代码块 ...
- JavaScript 循环判断练习题
JavaScript 循环判断练习题 小明有一组水果("苹果","梨子","香蕉","葡萄","西瓜" ...
- Go语言循环判断的使用~
Go 语言条件语句 条件语句需要开发者通过指定一个或多个条件,并通过测试条件是否为 true 来决定是否执行指定语句,并在条件为 false 的情况在执行另外的语句. 下图展示了程序语言中条件语句的结 ...
- 重读APUE(15)-pthread_cond_wait与while循环
即使pthead_cond_wait()和pthread_cond_timewait()没有错误返回,等待的条件也可能是假的:即使pthread_cond_timewait()返回了超时错误,关联的条 ...
- Spring的3级缓存和循环引用的理解
此处是我自己的一个理解,防止以后忘记,如若那个地方理解不对,欢迎指出. 一.背景 在我们写代码的过程中一般会使用 @Autowired 来注入另外的一个对象,但有些时候发生了 循环依赖,但是我们的代码 ...
随机推荐
- 【TP框架】包括TP3.1和3.2,自带缓存使用机制
原文章出处: http://blog.163.com/liwei1987821@126/blog/static/172664928201422133218356/ 写在开始:缓存变量和session变 ...
- 使用 Feed43
1.打开 Feed43 2.将标题.链接,时间等变化的字段删去用 {%} 代替.将固定且多余的字段删去用 {*} 代替.注意,源码中有换行的地方均需要添加{*} . 3.活学活用
- SQL语句面试题
一条SQL查询,一个表中按日期的累加数据如表: tmp_pay_amount pay_time amount 2013-11-1 10 2013-11-2 5 2013-11-3 4 2013-11- ...
- Evernote如何邮件分享
把你的笔记通过邮件发送给别人,从而实现分享
- Linux内核(1) - Kernel地图:Kconfig与Makefile
Makefile不是Make Love 从前在学校,混了四年,没有学到任何东西,每天就是逃课,上网,玩游戏,睡觉.毕业的时候,人家跟我说Makefile我完全不知,但是一说Make Love我就来劲了 ...
- http连接优化
http连接的性能优化 并行连接(能够同一时候和多台server建立HTTP连接) 持久连接 管道化连接 复用的连接 并行连接 长处: 并行连接能够在带宽资源充足的情况下同一时候建立多个HTTP连接, ...
- Python 元组 max() 方法
描述 Python 元组 max() 方法返回元组中元素最大值. 语法 max() 方法语法: max(T) 参数 T -- 指定的元组. 返回值 返回元组中元素最大值. 实例 以下实例展示了 max ...
- spineRunTime for cocos2dx v3 中动画播完删除animation
spineRunTime for cocos2dx v3 中删除animation,发现下面写法会崩溃: spine::SkeletonAnimation* animationNode = spi ...
- linux内存管理之DMA
说起DMA我们并不陌生,但是实际编程中去用的人不多吧,最多就是网卡驱动里的环形buffer,再有就是设备的dma,下面我们就分析分析. DMA用来在设备内存和内存之间直接数据交互.而无需cpu干预 ...
- 关于Linux动态库的加载路径
问题 按如下步骤在Ubuntu上编译安装Google Protocol Buffers $ ./configure $ make $ make check $ sudo make install 运行 ...