条件锁存在的意义:用生活中的例子秒懂线程间的"暗号系统"
条件锁存在的意义:用生活中的例子秒懂线程间的"暗号系统"
引子:
在学习linux下c语言中的互斥锁和条件锁的时候,我的大脑哦逻辑进入了“条件锁到底锁了什么”的死循环,所以让deepseek给我举了三个生动的例子,感觉非常有帮助,记录在这里,这段回答仅用于理解条件锁的含义,代码准确性有待验证:
正文:
一句话核心:条件锁(条件变量)就像线程间的"暗号",让线程在特定条件下自动休眠或唤醒,避免无意义的循环检查,极大节省CPU资源。下面用5个生活场景带你彻底理解!
一、快递柜场景:包裹到了才取货(生产者-消费者模型)
█ 场景还原
- 快递员(生产者线程):每天不定时放包裹到快递柜
- 用户(消费者线程):想取包裹,但不想每隔5分钟就跑下楼检查
█ 不用条件锁的问题
用户每隔5分钟就跑去快递柜输入取件码,发现没包裹又回家——CPU疯狂空转(忙等待),既费腿(CPU资源)又低效。
█ 使用条件锁的优化
// 全局条件变量(快递柜通知系统)
pthread_cond_t has_package = PTHREAD_COND_INITIALIZER;
// 用户取件线程
void* user_thread(void* arg) {{
pthread_mutex_lock(&lock);
while(快递柜为空) {{
// 进入休眠,直到收到快递员的通知
pthread_cond_wait(&has_package, &lock);
}}
取出包裹();
pthread_mutex_unlock(&lock);
}}
// 快递员线程
void* courier_thread(void* arg) {{
pthread_mutex_lock(&lock);
放入包裹();
// 投递完成,触发通知(类似快递柜发短信)
pthread_cond_signal(&has_package);
pthread_mutex_unlock(&lock);
}}
效果:用户回家睡觉,收到短信才下楼取件——CPU利用率从99%降到5%。
二、餐厅等位场景:有空桌才能吃饭
█ 场景还原
- 顾客(线程A):到餐厅发现满座
- 服务员(线程B):需要等顾客吃完才能安排新座位
█ 传统互斥锁的尴尬
顾客每隔1分钟就问服务员:"有空位了吗?" 服务员不断回答:"还没!" ——双方都累。
█ 条件锁的优雅方案
pthread_cond_t table_available = PTHREAD_COND_INITIALIZER;
// 顾客线程
void* customer(void* arg) {{
pthread_mutex_lock(&restaurant_lock);
while(餐桌数 == 0) {{
// 安静等待服务员叫号
pthread_cond_wait(&table_available, &restaurant_lock);
}}
入座就餐();
pthread_mutex_unlock(&restaurant_lock);
}}
// 服务员线程
void* waiter(void* arg) {{
pthread_mutex_lock(&restaurant_lock);
清理餐桌();
空桌数++;
// 广播通知所有等待顾客(类似叫号屏刷新)
pthread_cond_broadcast(&table_available);
pthread_mutex_unlock(&restaurant_lock);
}}
优势:顾客喝茶休息,服务员只在有空桌时统一通知,沟通效率提升10倍。
三、流水线场景:组装必须按顺序
█ 场景还原
- 工序A(线程1):生产手机外壳
- 工序B(线程2):安装屏幕,但必须等外壳完成后才能开工
█ 无协调的灾难
工序B的工人不断跑到工序A车间检查进度——大量时间浪费在跑路上(线程切换开销)。
█ 条件锁的工业级方案
pthread_cond_t case_ready = PTHREAD_COND_INITIALIZER;
// 工序B线程
void* install_screen(void* arg) {{
pthread_mutex_lock(&factory_lock);
while(外壳完成数 == 0) {{
// 产线工人去休息室等待
pthread_cond_wait(&case_ready, &factory_lock);
}}
安装屏幕();
pthread_mutex_unlock(&factory_lock);
}}
// 工序A线程
void* make_case(void* arg) {{
pthread_mutex_lock(&factory_lock);
生产外壳();
外壳完成数++;
// 铃铛一响,通知所有安装工
pthread_cond_signal(&case_ready);
pthread_mutex_unlock(&factory_lock);
}}
结果:工序B工人只在铃响时开工,整体生产效率提升40%。
四、为什么不用互斥锁+循环检查?
对比实验:CPU占用率实测
| 方案 | CPU占用率 | 响应延迟 |
|---|---|---|
| 纯互斥锁+usleep(1) | 25% | 1ms |
| 条件变量 | 0.3% | 0.1ms |
// 错误示范:忙等待消耗CPU
while(条件不满足) {{
pthread_mutex_unlock(&lock);
usleep(1000); // 让出CPU但仍有频繁切换
pthread_mutex_lock(&lock);
}}
结论:条件变量通过内核级休眠,比手动休眠减少 99%的线程唤醒次数。
五、条件锁的核心价值总结
- 消灭忙等待:让线程在条件不满足时主动让出CPU,而不是"占着茅坑不拉屎"
- 精准唤醒:通过
pthread_cond_signal或pthread_cond_broadcast控制唤醒策略 - 避免竞态条件:
pthread_cond_wait会自动释放锁+进入等待队列,保证唤醒后能重新获得锁 - 跨线程协作:像交通信号灯一样协调多个线程的执行顺序
下次看到pthread_cond_wait,就想象成线程在说:"这事我干不了,先睡会儿,有情况叫我!" ——这才是高效程序员的智慧。
条件锁存在的意义:用生活中的例子秒懂线程间的"暗号系统"的更多相关文章
- ThreadLocal实现session中用户信息 的线程间共享(精)
ThreadLocal并不难理解,我总结的最简单的理解就是: ThreadLocal像其它变量一样(局部.全局.静态)也是一种变量类型,只是他是线程变量,更直白的说他是一种变量作用域,即他的作用域是当 ...
- ThreadLocal实现session中用户信息 的线程间共享
转载自:http://blog.sina.com.cn/s/blog_4b5bc01101013gok.html ThreadLocal并不难理解,我总结的最简单的理解就是: ThreadLocal像 ...
- JAVA中管道通讯(线程间通讯)例子
Java I/O系统是建立在数据流概念之上的,而在UNIX/Linux中有一个类似的概念,就是管道,它具有将一个程序的输出当作另一个程序的输入的能力.在Java中,可以使用管道流进行线程之间的通信,输 ...
- 通过一个生活中的案例场景,揭开并发包底层AQS的神秘面纱
本文导读 生活中案例场景介绍 联想到 AQS 到底是什么 AQS 的设计初衷 揭秘 AQS 底层实现 最后的总结 当你在学习某一个技能的时候,是否曾有过这样的感觉,就是同一个技能点学完了之后,过了一段 ...
- 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁
问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...
- JS规则 我或你都可以 (逻辑或操作符)||逻辑或操作符,相当于生活中的“或者”,当两个条件中有任一个条件满足,“逻辑或”的运算结果就为“真”
我或你都可以 (逻辑或操作符) "||"逻辑或操作符,相当于生活中的"或者",当两个条件中有任一个条件满足,"逻辑或"的运算结果就为&quo ...
- InnoDB的锁机制浅析(二)—探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/插入意向锁)
Record锁/Gap锁/Next-key锁/插入意向锁 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Recor ...
- linux c 线程间同步(通信)的几种方法--互斥锁,条件变量,信号量,读写锁
Linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量.信号量和读写锁. 下面是思维导图: 一.互斥锁(mutex) 锁机制是同一时刻只允许一个线程执行一个关键部分的代码. 1 . ...
- 关于一点pthread_cond_t条件锁的思考以及实验
转:http://blog.csdn.net/aniao/article/details/5802015 APUE上,关于条件锁.其中有这么几条总结: 1.使用条件锁前必须先锁住对应的互斥锁. 2.条 ...
- Python的条件锁与事件共享
1:事件机制共享队列: 利用消息机制在两个队列中,通过传递消息,实现可以控制的生产者消费者问题要求:readthread读时,writethread不能写:writethread写时,readthre ...
随机推荐
- [docker逃逸] Privileged 特权模式逃逸复现
本文作者CVE-柠檬i CSDN:https://blog.csdn.net/weixin_49125123 博客园:https://www.cnblogs.com/CVE-Lemon 微信公众号:L ...
- hackmyvm Hades5变量劫持提权
在这个目录下有个./uid的程序 分别运行./uid 和 id 发现我们在 uid一行是有不一样的 我们猜测 在./uid里面他先用chown把我们的 uid改写成了anthea 然后运行id 然后再 ...
- 混元API的加密机制与原生集成实战
今天,我们将重点讨论在对接混元大模型时需要特别关注的几个要点.首先,最为关键的一点是,混元大模型的加密方式相比于其他大模型更为复杂和严密.在对接过程中,我们通常避免使用混元官方提供的SDK进行集成,主 ...
- ORACLE存储过程中使用游标+BULK COLLECT的应用
经过半天的折腾,编译通过调试结果正确,掌握此过程中的知识点,oracle存储过程编写就应用到了90%. CREATE OR REPLACE PROCEDURE JUNAN.P_IPT_QUOTN_IN ...
- 小程序uni-app处理input框将页面往上推动的解决办法
1. view <view class="bottom-wri-box" :style="{bottom: bottomHeight}"> < ...
- AI编程:如何编写提示词
这是小卷对AI编程工具学习的第2篇文章,今天讲讲如何编写AI编程的提示词,并结合实际功能需求案例来进行开发 1.编写提示词的技巧 好的提示词应该是:目标清晰明确,具有针对性,能引导模型理解问题 下面是 ...
- 从存钱罐到子数组:一个关于累加和的精妙问题|LeetCode 560 和为K的子数组
LeetCode 560 和为K的子数组 点此看全部题解 LeetCode必刷100题:一份来自面试官的算法地图(题解持续更新中) 生活中的算法 你有没有这样的经历:每天往存钱罐里存一些零钱,某一天突 ...
- LeetCode 第1题:两数之和
LeetCode 第1题:两数之和 题目描述 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标. 你可以 ...
- POI包操作Excel代码
1.创建工作簿 (WORKBOOK) HSSFWorkbook wb = new HSSFWorkbook(); FileOutputStream fileOut = new File ...
- vue-element-template去除登录
一.修改src目录下的permission.js文件 1.注释 //if (hasToken) { // if (to.path === '/login') { // // if is logged ...