OS / Linux / pthread_cond_wait 为什么需要传递 mutex 参数?
栗子:
mutex.lock();while (判断“条件”是否成立) {pthread_cond_wait 等待
}mutext.unlock();
条件变量这个互斥锁,不是用来保护条件变量的内部状态。而是用来保护外部“条件”(就是那个 while 循环中的判断)。假如条件变量的内部状态需要锁定,完全可以在内部实现中维护一个锁,没有必要从外部传进来。
用于判断是否等待的“条件”,通常就是线程之间共享的某个变量值。A 线程判断“条件”等待,会读取共享变量。B 线程让“条件”满足,会修改变量。这个锁,就是保护线程间的共享变量(“条件”),让“条件”不会一边修改,一边读取。
这把锁还有个额外的作用。wait 函数会阻塞,将线程 A 放到阻塞队列中。wait 函数放在锁的 lock,unlock 内部,也保证了线程还没有真正放到阻塞队列时,线程 B 不能修改“条件”后进行唤醒。这段话应该暂时读不懂,可回头再看,先放在这里,不然描述就不够准确。
不同的应用会有不同的“条件”,在实现条件变量这个库时,是没有办法预先知道这个“条件”究竟是什么。因此要保护“条件”,就只能让用户自己在库外部分配锁。
弄清了这个互斥锁究竟在保护什么。这时我们才能进一步讨论 pthread_cond_wait
为什么要传入这个锁呢?这点就跟 wait 的实现有关。
先来看等待线程 A 的写法。
mutex.lock();while (判断“条件”是否成立) {pthread_cond_wait 等待
}mutext.unlock();
判断“条件”是否成立,在 lock, unlock 之间受到保护。pthread_cond_wait
可能会阻塞,假如真的阻塞,mutex 这锁就一直不能被释放了。因此在 pthread_cond_wait
的实现内部,在阻塞之前,必须先将锁释放。在唤醒的时候,再重新获取锁。
将 pthread_cond_wait
展开,内部实现中,会有下面的过程。
做一些其它事情
mutext.unlock()
阻塞中...
唤醒
mutext.lock()
假如在线程 A 中完全展开 pthread_cond_wait
。
mutex.lock();while (判断“条件”是否成立) {做一些其它事情mutext.unlock()阻塞唤醒mutext.lock()
}mutext.unlock();
可以看到,判断“条件” 一直在 mutext 的 lock, unlock 之间,受到保护。
来到这里,我们总结一下。
- 跟条件变量关联的互斥锁,是用于保护判断“条件”,并非条件变量的内部状态。
- 将互斥锁,传入 wait 的实现中,是让条件变量库可以在适当的时机释放(unlock)和重新获取(lock)这把锁。
注意上面第 2 点中,“适当时机”这个词。假如不将这个锁传入 pthread_cond_wait,让用户自己在阻塞前先释放锁,是没有办法做到适当时机的。阻塞队列在条件变量库内部维护,只有条件变量库内部才能控制这个时机。
wait 会阻塞,将线程 A 放到阻塞队列中。在线程还没有真正放到阻塞队列时,需要一直上锁。不然另一线程 B 修改“条件”后进行唤醒,这个线程 A 还没有在阻塞队列中,就不能被唤醒了。因而这把保护外部判断“条件”的锁,需要传入到 wait 函数中。等将线程真正放到阻塞队列后才能解锁,之后线程被唤醒后再重新获取。
线程 A 的 pthread_cond_wait
需要传入 mutext,并且 pthread_cond_wait
一定要在 lock 和 unlock 之间。
至于线程 B, 用于修改“条件”。修改“条件” 也必须在 lock 和 unlock 之间,受互斥锁保护。至于 pthread_cond_signal
是否在 lock 和 unlock 之间,其实是没有关系的。但 pthread_cond_signal
必须在修改“条件”之后,不然可能 A 线程被唤醒后,条件不满足继续等待,这个唤醒信号就丢失了。
mutext.lock()
修改”条件“
pthread_cond_signal 唤醒
mutext.unlock()
也可以将 pthread_cond_signal
移到 unlock 外部。
mutext.lock()
修改”条件“
mutext.unlock()
pthread_cond_signal 唤醒
条件变量等待时,那个 wait 的判断,需要使用 while 循环,而不是 if,是防止虚假唤醒。就不再一一分析了。
作者:黄兢成
链接:https://www.zhihu.com/question/24116967/answer/676751734
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
(SAW:Game Over!)
OS / Linux / pthread_cond_wait 为什么需要传递 mutex 参数?相关推荐
- u-boot向linux内核传递启动参数
U-BOOT 在启动内核时,会向内核传递一些参数.而这些参数是通过 structtag来传递的. U-boot 把要传递给 kernel 的东西保存在 struct tag数据结构中,启动 kerne ...
- liunx 上get 不到url参数 java_URL传递中文参数,大坑一枚,Windows与Linux效果竟然不一致...
下午,计划2个小时搞定,个人官网第6次升级,就可以干点轻松的事了,结果,下午多搞了2个小时,晚上又搞了2个小时,才搞定.最后一个世界难题是,URL传递中文参数.问题大致是这么出现的:我为"博 ...
- linux中probe函数传递参数的寻找(下)
点击打开链接 linux中probe函数传递参数的寻找(下) 通过追寻driver的脚步,我们有了努力的方向:只有找到spi_bus_type的填充device即可,下面该从device去打通,当两个 ...
- linux中probe函数中传递的参数来源(上)
点击打开链接 上一篇中,我们追踪了probe函数在何时调用,知道了满足什么条件会调用probe函数,但probe函数中传递的参数我们并不知道在何时定义,到底是谁定义的,反正不是我们在驱动中定义的(当然 ...
- linux下c语言线程传参数,【linux】C语言多线程中运行线程池,在线程池中运行线程池,,传递的结构体参数值为空/NULL/0...
C语言多线程中运行线程池,在线程池中运行线程池,,传递的结构体参数值为空/NULL/0 本贴问题,之前已经提问过一次,当时已经解决了,原贴在这里https://segmentfault.com/q/1 ...
- Linux基本命令之date命令的参数及获时间戳的方法
这篇文章主要为大家介绍了Linux基本命令中的date命令的参数及获时间戳的方法,在本文中列举了4个获取时间戳的方法,需要的朋友可以参考下 1.时间命令:date 向date命令传递参数适用'+'(加 ...
- 使用ajax发送数组请求,Ajax请求传递数组参数
var ids = []; var rows=$("#tt").datagrid("getSelections"); for(var i=0; i ids.pu ...
- linux 内核学习11-内核模块参数
linux 内核学习11-内核模块参数 内核模块作为一个可拓展的动态模块,为Linux内核提供灵活性,所以需要依据不同的场景来传递不同的参数,实现不同的功能 1. 准备工作 #define modul ...
- OS + linux command / Linux Command / Linux command / linux Command
写下你职业生涯中最难以忘怀的误操作.. http://www.dangkai.com/ArticlePage/Article59549.htm http://bbs.chinaunix.net/thr ...
最新文章
- 详解VirtualBox虚拟机网络环境解析和搭建-NAT、桥接、Host-Only、Internal、端口映射
- 【M25】将构造方法和非成员方法虚化
- 说学习前端开发简单,如何才能成功上岸?
- [转载] 如何用python实现一行两个输入
- EMNLP 2021 | 罗氏和博阿齐奇大学研究合作团队提出:多标签文本分类中长尾分布的平衡策略...
- vue $slot基本用法
- 推荐十大国外IT网站
- java svg等值线_带有颜色填充的等值线画法研究
- Windows 10 未安装任何音频输出设备 解决方案
- 【分享】地产集团公司LOGO设计
- STM32H750移植STemWin,驱动ST7789
- 强化学习——股票预测项目复现
- Vue2.0 —— 运用算法实现 AST 抽象语法树
- PHPMyWind5.4存储XSS(CVE-2017-12984)
- 软件测试知识点和面试题--手工测试篇(功能测试)
- Drawio免费绘图工具
- 选择java大数据开发方向学习,应该怎么规划学习路线
- 电脑检查内存条型号的方法
- 为docker设置国内镜像
- oracle查询job号,oracle job号使用
热门文章
- express4.x中的链式路由句柄
- iptables实现网络防火墙及地址转换
- 转载收藏之用 - 微信公众平台开发教程(三):微信公众平台开发验证
- VoIP安全问题解析
- 【实用技能】通过sh脚本动态上传项目到github
- 2020 操作系统第一天复习(习题总结)
- linux deepin “debconf: DbDriver “config“: config.dat 被另一个进程锁定:资源暂时不可用“
- minio扩展现有的分布式集群:扩大集群规模,增加磁盘数量
- Hadoop Hive导入数据命令
- Flink流计算WordCount代码示例