当前位置: 首页 > news >正文

【基础分析】——线程、锁、条件变量

先理解核心场景:生产者-消费者模型

这段代码模拟的是生活中工厂生产商品,顾客消费商品的场景:

  • 生产者线程:负责往仓库(队列)里放商品(数字)
  • 消费者线程:负责从仓库里取商品(数字)
  • 核心问题:要保证仓库不会被同时操作(比如生产和消费撞车),消费者不会去拿空仓库里的东西

逐部分拆解代码(零基础友好版)

1. 全局变量:公共资源
std::queue<int>q;// 仓库(队列),存数字(商品)std::mutex mtx;// 仓库的锁,只有拿到锁才能动仓库std::condition_variable cv;// 通知器:生产者喊消费者“有货了”
  • 队列q:像排队买奶茶,先放进去的数字先被拿出来(先进先出)
  • mtx:仓库门的钥匙,同一时间只有一个人能拿到钥匙开门
  • 条件变量cv:生产者喊“仓库有货了,快来取!”
2. 生产者函数:生产商品
voidproducer(){// 生产9个数字(0-8)for(inti=0;i<9;i++){{// 这个大括号是“锁的作用范围”,出了括号自动解锁// 上锁:拿到仓库钥匙,别人暂时不能动仓库std::lock_guard<std::mutex>lock(mtx);q.push(i);// 把数字i放进仓库std::cout<<"生产"<<i<<std::endl;// 打印生产信息}// 解锁:用完钥匙,还回去Sleep(1000);// 休息1秒(模拟生产需要时间)cv.notify_one();// 喊一声:有货了,通知消费者}}

通俗解释

  • 生产者每次生产一个数字,先拿钥匙打开仓库门(上锁),把数字放进去,然后还钥匙(解锁)
  • 生产一个歇1秒(模拟真实生产耗时)
  • 生产完喊一声,告诉消费者“有新货了”
3. 消费者函数:消费商品
voidconsumer(){// 死循环:一直等着消费,直到消费到6就退出while(1){// 上锁:拿仓库钥匙(unique_lock是可以临时解锁的锁,适合等通知)std::unique_lock<std::mutex>lock(mtx);// 等通知:如果仓库空,就放下钥匙等;仓库有货了,再拿钥匙继续cv.wait(lock,[](){return!q.empty();});// 仓库有货了,开始消费intv=q.front();// 取仓库里第一个商品q.pop();// 把这个商品从仓库拿走std::cout<<"消费"<<v<<std::endl;// 打印消费信息// 消费到6就停止(退出死循环)if(v==6)break;}}

通俗解释

  • 消费者一直等着,先拿钥匙,但如果仓库空了,就把钥匙放下,等着生产者喊“有货了”
  • 等生产者喊了之后,再拿钥匙,从仓库里取第一个数字,拿走并打印
  • 只要拿到数字6,就不消费了,直接走人
4. 主函数:启动程序
intmain(){// 创建两个线程:t1是生产者,t2是消费者std::threadt1(producer);std::threadt2(consumer);// 等待线程结束:主线程等t1、t2都干完活,再结束程序t1.join();t2.join();return0;}

通俗解释

  • 老板(main函数)招了两个员工:t1负责生产,t2负责消费
  • join():老板不先走,等两个员工都干完活,再关门下班

代码运行过程(零基础能懂的流程)

  1. 程序启动,同时启动生产者和消费者线程
  2. 生产者先生产0 → 歇1秒 → 喊消费者;消费者拿到0,消费0
  3. 生产者生产1 → 歇1秒 → 喊消费者;消费者拿到1,消费1
  4. 以此类推,直到生产者生产6,消费者消费6后,直接退出(不再消费)
  5. 生产者还会继续生产7、8,但消费者已经走了,这两个数字会留在仓库里
  6. 生产者生产完9个数字后也退出,程序结束

总结(核心要点)

  1. 线程:就是同时干两件事(生产和消费),像工厂里的两个工人;
  2. 锁(mutex):保护公共仓库,防止生产和消费同时操作,避免乱套;
  3. 条件变量(cv):解决“消费者白等”问题,生产者有货了才通知消费者,不用消费者一直傻等。
http://www.jsqmd.com/news/520055/

相关文章:

  • ArduinoHttpClient嵌入式HTTP通信实战指南
  • Qwen-Audio方言合成突破:地道粤语生成
  • BurstSPI:STM32F103RB高速SPI批量传输优化库
  • Realistic Vision V5.1 虚拟摄影棚提示词工程:从入门到精通的全攻略
  • 手把手教你“养龙虾”:OpenClaw从零部署到高阶应用全攻略
  • 通达信HSL_QD副图指标保姆级导入教程:手把手教你用换手率+量比双指标看盘
  • AI文档管理踩坑记:我们如何用Airflow调度,把Cursor产出自动归位到Confluence和TAPD
  • 从物理引擎到Material Design:深入理解Android插值器(Interpolator)的设计哲学
  • XLR8AddrPack:FPGA-ARM异构平台的硬件地址契约库
  • React 核心工作流程两阶段:Render 阶段和 Commit 阶段
  • C语言实现CAN FD高可靠通信:手把手教你绕过ISO 11898-1:2015标准陷阱的7个关键配置点
  • Python模块与包管理完全指南:从入门到精通
  • JDK 26 正式发布:十一大新特性深度解读
  • 2026年最新最全Java面试题汇总汇一览表!
  • GLM-OCR入门:3步完成CSDN星图GPU平台一键部署与测试
  • 苍穹外卖day02记录
  • 《动手学深度学习》-69BERT预训练实现
  • MiniMax M2.7 完成你的不可能,但缺不认识马嘉祺
  • java毕业设计基于springboot昆嵛山国家级自然保护区林业资源信息管理系统
  • SLAM数据集实战:如何利用TUM、KITTI、EuRoC的真实轨迹文件进行算法评估与优化
  • 二维静态表达到三维动态建模:仓储空间管理能力的结构性升级—— 基于镜像视界“像素即坐标”与轨迹建模的空间智能体系
  • ROS2实战:当CMU自主探索算法遇上Livox MID-360,我是如何搞定实车部署的?
  • Hunyuan-MT-7B-WEBUI问题解决:部署常见错误与一键修复方案
  • 解锁FreeSWITCH隐藏功能:用API实现智能电话会议自动化
  • Activiti审批流避坑指南:SpringBoot整合时${}和#{}的5个易错点
  • CoPaw模型效果深度解析:生成高质量技术文档与代码注释
  • nRF51 SDK超低功耗BLE开发核心架构与实战
  • nlp_structbert_sentence-similarity_chinese-large 服务监控与日志排查指南
  • 用Python重现经典:Theil-Sen与Mann-Kendall分析遥感NPP数据(附完整代码与结果解读)
  • 手写签名提取工具(图片)