Linux 条件变量使用细节(为何调用 pthread_cond_wait 前加锁,函数内部解锁,返回时又加锁)
一、本文目的
首先说明,本文重点不在怎么用条件变量。这里我先列出 apue 中对于pthread_cond_wait函数的这么一段话:
调用者把锁住的互斥量传给函数,函数然后自动把调用线程放到等待条件的线程列表上,**对互斥量解锁。**这就关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道,这样线程就不会错过条件的任何变化。pthread_cond_wait返回时,互斥量再次被锁住。
这段话的信息量很大,其中关于互斥量的操作可以理解为以下三个点:
调用 pthread_cond_wait 前需要先对互斥量 mutex 上锁,才能把 &mutex 传入 pthread_cond_wait 函数。
在 pthread_cond_wait 函数内部,会首先对传入的 mutex 解锁。
当等待的条件到来后,pthread_cond_wait 函数内部在返回前会去锁住传入的 mutex 。
我当时看到这里,各种疑问,传入前为何要锁,传入后为何要释放,返回时又为何再次锁?
本文就这三个问题进行详细解释。不过在此之前,我们需要了解为什么要有条件变量。即条件变量的作用。
二、为何需要条件变量
如果没有条件变量,那么我们等待一个条件满足则会是下面这样的模型:
首先加锁进入临界区去查看条件是否满足,不满足则解锁离开临界区,睡眠一段时间再继续循环判断。在这种情况下如果刚离开临界区,条件变为满足,那么线程必须还要等一段时间重新进入临界区才能知道条件满足(如果在这段时间内,条件依旧一直保持满足的话),如果这一小段时间条件又变为不满足,那么这个线程还要继续循环判断。、
不断地加锁解锁(会影响使用同一把锁的其他线程),还不能第一时间收到条件满足。这种模型既费时又开销大。
所以条件变量的产生,正是为了不循环加锁解锁,并且第一时间收到条件满足的通知。
三、三个问题
要回答那三个问题,那么首先需要明白等待与唤醒的配合。
下图是我参考其他人的图(原图有误)更正后所画的。其实这个图就能解释那三个问题:pthread_cond_wait传入前为何要锁,传入后为何先解锁,以及返回前为何再锁。不过我还是详细解释一下。
图中有一个关键点,就是判断条件是否满足,是在调用 pthread_cond_wait 之前,上锁之后,就是说 pthread_cond_wait 不具备判断条件的能力,需要我们在外部写判断语句。
条件不满足时,才会进入 pthread_cond_wait 。
进入 pthread_cond_wait 先解锁就马上阻塞。
pthread_cond_signal 唤醒的是阻塞在 pthread_cond_wait 的进程。
可以结合下面的代码会更清楚。
以下 pthread_cond_wait 和 pthread_cond_signal 的通常用法的伪代码(条件为:value 是不是大于 0:
lock(&mutex);
while(value<=0)//需要value>0所以 value<=0就条件不满足
{pthread_cond_wait(&cond,&mutex);//条件满足,进行相关处理。
}
unlock(&mutex);
lock(&mutex);
if(value==0)
{value++;
}
if(value>0)
{pthread_cond_signal(&cond);
}
unlock(&mutex);
把这个基本流程弄清楚后,就可以解释那三个问题了。
四、传入前锁 mutex
为了方便大家观看,每个问题的解释我都会再次把上图贴出。
传入前锁 mutex 是为了保证线程从条件判断到进入 pthread_cond_wait 前,条件不被改变。
如果没有传入前的锁。就会有这样的情况:线程 A 判断条件不满足之后,调用 pthread_cond_wait 之前,A 因为休眠,或者因为多线程下,多个线程执行顺序和快慢的因素,令线程 B 更改了条件,使得条件满足。但此时线程 A 还没有调用 pthread_cond_wait。等到线程 A 又启动调用 pthread_cond_wait 后虽然条件满足,但却收不到 pthread_cond_signal 的唤醒,就一直阻塞下去。
五、传入后解锁 mutex
传入后解锁是为了条件能够被改变。
传入后的解锁,是因为调用 pthread_cond_signal 的那部分,需要先加锁更改条件后才调用pthread_cond_signal。(更改条件与等待条件满足,都是针对条件这一个资源的竞争,所以调用 pthread_cond_wait 和调用 pthread_cond_signal 的两个线程需要同一把锁)
如果 pthread_cond_wait 内不对 mutex 解锁,那么在调用 pthread_cond_wait 后,其他线程就不能更改条件,条件就会一直不满足。
六、返回前再次锁 mutex
返回前再次锁 mutex 是为了保证线程从 pthread_cond_wait 返回后到再次条件判断前不被改变。
保证在 pthread_cond_signal 之后与解锁 mutex 之间可能需要的其他语句能够执行。
对于 1,这里的理由与传入 pthread_cond_wait 前锁 mutex 的理由差不多。如果不锁,那么线程 A 调用 pthread_cond_wait 后,条件满足,线程 A 被唤醒,从 pthread_cond_wait 返回。线程 B 在此时更改了条件,使得条件不满足。线程 A 并不知道条件又被更改,还是以为条件满足,就可能出错。
对于 2,只要在 pthread_cond_signal 之后与解锁 mutex 之间有其他语句需要执行,那么由于 mutex 在这时已经被这个线程锁,还没有解锁,所以调用 pthread_cond_wait 的那个线程在pthread_cond_wait 返回前的锁 mutex 的行为就会阻塞,直到 pthread_cond_signal 后的语句执行完解锁,pthread_cond_wait 才会返回。
说到这里就顺便说一下,由于pthread_cond_wait返回再次锁的行为,pthread_cond_signal不一定放在 lock()和unlock()中间。
pthread_cond_signal的两种写法
lock(&mutex);
//一些操作
pthread_cond_signal(&cond);
//一些操作
unlock(&mutex);
缺点:在某些线程的实现中,会造成等待线程从内核中唤醒(由于cond_signal)回到用户空间,然后 pthread_cond_wait 返回前需要加锁,但是发现锁没有被释放,又回到内核空间所以一来一回会有性能的问题。
但是在 LinuxThreads 或者 NPTL 里面,就不会有这个问题,因为在 Linux 线程中,有两个队列,分别是 cond_wait 队列和 mutex_lock 队列, cond_signal 只是让线程从 cond_wait 队列移到 mutex_lock队列,而不用返回到用户空间,不会有性能的损耗。所以Linux中这样用没问题。
lock(&mutex);
//一些操作
unlock(&mutex);
pthread_cond_signal(&cond);
优点:不会出现之前说的那个潜在的性能损耗,因为在 signal 之前就已经释放锁了。
缺点:如果 unlock 之后 signal 之前,发生进程交换,另一个进程(不是等待条件的进程)拿到这把梦寐以求的锁后加锁操作,那么等最终切换到等待条件的线程时锁被别人拿去还没归还,只能继续等待。
七、尾语
总的来说,条件变量带个锁的目的就是让等待条件成立的线程不会丢掉条件成立的情况。
以上
转载于:https://blog.csdn.net/shichao1470/article/details/89856443
(SAW:Game Over!)
Linux 条件变量使用细节(为何调用 pthread_cond_wait 前加锁,函数内部解锁,返回时又加锁)相关推荐
- Linux先发送条件变量,浅谈Linux条件变量的使用
Linux线程同步之间存在多种机制,条件变量是一种类似操作系统里提到的生产者-消费者算法的同步机制,允许线程以无竞争的方式等待特定条件的发生. 示例伪代码: void* Thread1(void){ ...
- Linux先发送条件变量,linux 条件变量 浅谈Linux条件变量的使用
想了解浅谈Linux条件变量的使用的相关内容吗,在本文为您仔细讲解linux 条件变量的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:linux,条件变量,下面大家一起来学习吧. Linu ...
- 理解 Linux 条件变量
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/cheungmine/article/details/37317429 理解 Linux 条件变量 1 ...
- 深入理解Linux 条件变量2:使用条件变量实现[生产-消费]框架
前言 在上一篇文章<深入理解Linux 条件变量1:使用场景.接口说明>我们简单介绍了条件变量的使用场景以及相关接口,正如大神linus所说:talk is cheap,show me t ...
- 深入理解Linux 条件变量3:条件变量为什么要配合着锁使用?
在上一篇文章<深入理解Linux 条件变量2:使用条件变量实现[生产-消费]框架>中,我们通过示例代码演示了条件变量的使用.从条件变量的API接口中我们很容易发现,条件变量必须配合着互斥锁 ...
- linux条件变量使用和与信号量的区别
linux条件变量使用和与信号量的区别 今天在学习进程同步机制的时候看见一句话: 条件变量只能在管程中通过两个原语操作--wait原语和signal原语 于是发出了一个疑问:信号量机制和条件变量同步机 ...
- Linux条件变量(pthread_cond)示例
条件变量详解 如果线程正在等待某个特定条件发生,它应该如何处理这种情况?它可以重复对互斥对象锁定和解锁,每次都会检查共享数据结构,以查找某个值.但这是在浪费时间和资源,而且这种繁忙查询的效率非常低.解 ...
- Linux 条件变量详解
LINUX条件变量详解 一.条件变量概述 1.1 函数API讲解 二.函数使用 三.结果展示与分析 一.条件变量概述 条件变量不是一个把锁,它实质上一个类似信号的东西,与锁相互配合使用,因为锁所能 ...
- Linux 条件变量 pthread_cond_wait
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起:另一个线程使"条件成立"(给出条件成立信号). ...
最新文章
- 计算机书籍-机器学习导论(原书第2版)
- Linux C编程--线程操作3--线程属性解析
- 3.7 非极大值抑制-深度学习第四课《卷积神经网络》-Stanford吴恩达教授
- 比iPhone8更重要的新App Store,给内容产品的未来指出明路
- 我会永远永远的爱你,直到你不爱我的那一天
- 严蔚敏算法约瑟夫环_极客算法训练笔记(三),链表详细图解,别再逃避了朋友...
- response.addCookie(cookie);报错分析
- 当往日悄然走远,只留下清澈的心
- matlab数组 xp,windowsxp系统将matlab数据导入excel的方法
- 百草味荣获“食品安全诚信单位“奖 食品安全质量获行业肯定
- VC的静态链接库 动态链接库
- 一文带你学会python新年倒计时
- 大学物理电磁学——磁场两条定理
- mysql分组取出每组地一条数据_MYSQL实现分组排序并取组内第一条数据
- 大学生变身建筑工人:在家隔离的美国学生们,正在Minecraft中复现一座座大学校园
- 小黄人代码(Python)
- cisco命令防ping_Cisco基本命令配置
- 软件安全理论测试部分
- 【转载】大学四年我是如何学习程序设计的
- 学通信工程考计算机等级证书,通信工程专业可以考什么证书