pthread_cond_wait函数的学习以及其他
pthread_cond_wait() 前使用 while 讲解
2009-10-27 9:33
LINUX环境下多线程编程肯定会遇到需要条件变量的情况,此时必然要使用pthread_cond_wait()函数。但这个函数的执行过程比较难于理解。
pthread_cond_wait()的工作流程如下(以MAN中的EXAMPLE为例):
Consider two shared variables x and y, protected by the mutex mut, and a condition vari-
able cond that is to be signaled whenever x becomes greater than y.
int x,y;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
Waiting until x is greater than y is performed as follows:
pthread_mutex_lock(&mut);
while (x <= y) {
pthread_cond_wait(&cond, &mut);
}
/* operate on x and y */
pthread_mutex_unlock(&mut);
Modifications on x and y that may cause x to become greater than y should signal the con-
dition if needed:
pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mut);
这个例子的意思是,两个线程要修改X和Y的值,第一个线程当X<=Y时就挂起,直到X>Y时才继续执行(由第二个线程可能会修改X,Y的值,当X>Y时唤醒第一个线程),即首先初始化一个普通互斥量mut和一个条件变量cond。之后分别在两个线程中分别执行如下函数体:
pthread_mutex_lock(&mut);
while (x <= y) {
pthread_cond_wait(&cond, &mut);
}
/* operate on x and y */
pthread_mutex_unlock(&mut);
和: pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mut);
其实函数的执行过程非常简单,在第一个线程执行到pthread_cond_wait(&cond,&mut)时,此时如果X<=Y,则此函数就将mut互斥量解锁,再将cond条件变量加锁,此时第一个线程挂起(不占用任何CPU周期)。
而在第二个线程中,本来因为mut被第一个线程锁住而阻塞,此时因为mut已经释放,所以可以获得锁mut,并且进行修改X和Y的值,在修改之后,一个IF语句判定是不是X>Y,如果是,则此时pthread_cond_signal()函数会唤醒第一个线程,并在下一句中释放互斥量mut。然后第一个线程开始从pthread_cond_wait()执行,首先要再次锁mut,如果锁成功,再进行条件的判断(至于为什么用WHILE,即在被唤醒之后还要再判断,后面有原因分析),如果满足条件,则被唤醒进行处理,最后释放互斥量mut。
至于为什么在被唤醒之后还要再次进行条件判断(即为什么要使用while循环来判断条件),是因为可能有“惊群效应”。有人觉得此处既然是被唤醒的,肯定是满足条件了,其实不然。如果是多个线程都在等待这个条件,而同时只能有一个线程进行处理,此时就必须要再次条件判断,以使只有一个线程进入临界区处理。对此,转来一段:
引用下POSIX的RATIONALE:
Condition Wait Semantics
It is important to note that when pthread_cond_wait() and pthread_cond_timedwait() return without error, the associated predicate may still be false. Similarly, when pthread_cond_timedwait() returns with the timeout error, the associated predicate may be true due to an unavoidable race between the expiration of the timeout and the predicate state change.
The application needs to recheck the predicate on any return because it cannot be sure there is another thread waiting on the thread to handle the signal, and if there is not then the signal is lost. The burden is on the application to check the predicate.
Some implementations, particularly on a multi-processor, may sometimes cause multiple threads to wake up when the condition variable is signaled simultaneously on different processors.
In general, whenever a condition wait returns, the thread has to re-evaluate the predicate associated with the condition wait to determine whether it can safely proceed, should wait again, or should declare a timeout. A return from the wait does not imply that the associated predicate is either true or false.
It is thus recommended that a condition wait be enclosed in the equivalent of a "while loop" that checks the predicate.
从上文可以看出:
1,pthread_cond_signal在多处理器上可能同时唤醒多个线程,当你只能让一个线程处理某个任务时,其它被唤醒的线程就需要继续wait,while循环的意义就体现在这里了,而且规范要求pthread_cond_signal至少唤醒一个pthread_cond_wait上的线程,其实有些实现为了简单在单处理器上也会唤醒多个线程.
2,某些应用,如线程池,pthread_cond_broadcast唤醒全部线程,但我们通常只需要一部分线程去做执行任务,所以其它的线程需要继续wait.所以强烈推荐此处使用while循环.
其实说白了很简单,就是pthread_cond_signal()也可能唤醒多个线程,而如果你同时只允许一个线程访问的话,就必须要使用while来进行条件判断,以保证临界区内只有一个线程在处理。
近期学习了线程等待和激活的相关知识。
先介绍几个api:
pthread_cond_t表示多线程的条件变量,用于控制线程等待和就绪的条件。
一:条件变量的初始化:
条件变量和互斥锁一样,都有静态动态两种创建方式,
静态方式使用PTHREAD_COND_INITIALIZER常量初始化。
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
动态方式初始化:
1 首先要new或者malloc一个pthread_cond_t类型变量,
用完后记得delete或者free掉。
2
使用pthread_cond_wait方式如下:
pthread _mutex_lock(&mutex)
while或if(线程执行的条件是否成立)
pthread_cond_wait(&cond, &mutex);
线程执行
pthread_mutex_unlock(&mutex);
对于这点apue给出的解释:The mutex passed to pthread_cond_wait protects the condition.The caller passes it locked to
the function, which then atomically places the calling thread on the list of threads waiting for the condition and unlocks
the mutex. This closes the window between the time that the condition is checked and the time that the
thread goes to sleep waiting for the condition to change, so that the thread doesn't miss a change in the condition.
When pthread_cond_wait returns, the mutex is again locked.
1,线程放在等待队列上,解锁
2,等待 pthread_cond_signal或者pthread_cond_broadcast信号之后去竞争锁
3,若竞争到互斥索则加锁。
使用流程
等待线程:
pthread_mutex_lock(&mutex);
if(条件不满足)
pthread_cond_wait(&cond, &mutex);
//处理共享资源
pthread_mutex_unlock(&mutex);
激活线程:
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
https://www.cnblogs.com/leijiangtao/p/4028338.html
https://www.cnblogs.com/secondtonone1/p/5580203.html
https://blog.csdn.net/analogous_love/article/details/53319815
pthread_cond_wait函数的学习以及其他的更多相关文章
- Hive自定义函数的学习笔记(1)
前言: hive本身提供了丰富的函数集, 有普通函数(求平方sqrt), 聚合函数(求和sum), 以及表生成函数(explode, json_tuple)等等. 但不是所有的业务需求都能涉及和覆盖到 ...
- (转载)prepare函数的学习,我要学习php第二天
(转载)http://www.boyuan78.com/htm/company/2012_1030_60.html prepare函数的学习,我要学习php第二天 $mysqli = new mysq ...
- QT QObject::connect函数的学习
从Qobject(QObject.h)源码中可以看到QObject::connect的定义是这样的: static bool connect(const QObject *sender, cons ...
- pthread_cond_wait() 函数的使用
1. 首先pthread_cond_wait 的定义是这样的 The pthread_cond_wait() and pthread_cond_timedwait() functions are us ...
- Matlab中常见的神经网络训练函数和学习函数
一.训练函数 1.traingd Name:Gradient descent backpropagation (梯度下降反向传播算法 ) Description:triangd is a networ ...
- 互斥量、条件变量与pthread_cond_wait()函数的使用,详解(一)
1. 首先pthread_cond_wait 的定义是这样的 The pthread_cond_wait() and pthread_cond_timedwait() functions are us ...
- python函数基础学习
函数的定义与调用: def 函数名(参数1,参数2): ‘’’函数注释’’’ print(‘函数体’) return 返回值 定 义:def关键字开关,空格之后接函数名和圆括号,最后冒号结尾 def ...
- R语言函数化学习笔记6
R语言函数化学习笔记 1.apply函数 可以让list或者vector的元素依次执行一遍调用的函数,输出的结果是list格式 2.sapply函数 原理和list一样,但是输出的结果是一个向量的形式 ...
- R语言函数化学习笔记3
R语言函数化学习笔记3 R语言常用的一些命令函数 1.getwd()查看当前R的工作目录 2.setwd()修改当前工作目录 3.str()可以输出指定对象的结构(类型,位置等),同理还有class( ...
随机推荐
- C++ 中 const 使用
如果你一看见C++中const就脱口而出:“常量!”那只能说明你对c++不甚了解.或者说你太2了. const得一些使用方法与场景如下: 1:const修饰普通变量,全局变量,静态变量 ; ; 变量保 ...
- 数据结构_Search
问题描述 可怜的 Bibi 刚刚回到家,就发现自己的手机丢了,现在他决定回头去搜索自己的手机.现在我们假设 Bibi 的家位于一棵二叉树的根部.在 Bibi 的心中,每个节点都有一个权值 x,代表他心 ...
- DBUtils工具类和DBCP连接池
今日内容介绍 1.DBUtils2.处理结果集的八种方式3.连接池4.连接池的用法1 PrepareStatement接口预编译SQL语句 1.1 预处理对象 * 使用PreparedStatemen ...
- SharpCompress压缩和解压缩,并解决压缩的中文乱码问题
一.下载SharpCompress库 二.解压缩 (1)不带密码 /// <summary> /// 解压缩(支持rar,zip) /// </summary> /// < ...
- 【转载】在AspNetCore 中 使用Redis实现分布式缓存
原文地址:https://www.cnblogs.com/szlblog/p/9045209.html AspNetCore 使用Redis实现分布式缓存 上一篇讲到了,Core的内置缓存:IMemo ...
- position用法
fixed的用法 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- 转载Json和Xml的区别,以及它们的底层是如何处理的
XML:可扩展标记语言 JSON:轻量级的数据交换格式 区别: 1.可读性方面:基本相同,Xml的可读性较好些: 2.可扩展性方面:都有较好的扩展性: 3.编码难度方面:json的编码较容 ...
- C# 添加,修改,删除Xml节点
//添加xml节点 private void AddXml(string image, string title) { XmlDocument xmlDoc = new X ...
- t-sql read xlsx
How to Read and Load an Excel 2007 or Excel 2010 File Without Using Import/Export Utility To read an ...
- 10.18 NOIP2018提高组模拟题(二)
大水题 1.咒语 (curse.pas/c/cpp) [题目描述] 亮亮梦到自己来到了魔法城堡,但一扇巨大的石门阻拦了他通向城堡内的路.正当他沮丧之际,突然发现门上有一处机关,机关上有一张很长的纸条. ...