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

C++ 条件变量 condition_variable

condition_variable是 C 标准库中用于多线程同步的核心头文件。它主要提供了条件变量Condition Variable机制用来协调多个线程的执行顺序。简单来说它的作用就是让一个或多个线程在特定条件不满足时进入休眠阻塞等待直到另一个线程修改了共享状态并发出通知唤醒等待的线程才会继续执行。 为什么需要它在没有条件变量的情况下如果一个线程需要等待某个条件比如等待队列里有数据通常只能采用“忙等待”不断循环检查或“定时休眠检查”的方式。这两种方式都会大量浪费 CPU 资源或导致响应延迟。使用condition_variable可以让线程在没有任务时完全释放 CPU 资源进入睡眠只有在真正需要工作时才被精准唤醒从而极大提高程序的运行效率。️ 头文件里的核心组件这个头文件主要包含了以下几个关键类和函数std::condition_variable最常用的条件变量类必须配合std::unique_lockstd::mutex使用。std::condition_variable_any更通用的条件变量可以配合任何满足基本要求的锁使用但性能开销稍大。cv_status枚举类用于表示带超时的等待是否是因为超时返回的。notify_all_at_thread_exit功能函数用于安排在当前线程退出时通知所有等待的线程。⚙️ 核心工作机制条件变量的使用通常离不开互斥锁std::mutex其核心操作主要分为“等待”和“通知”两类1. 等待方消费者线程wait(lock)调用前必须先持有锁。调用后线程会自动释放锁并进入阻塞状态。当被唤醒时它会重新尝试获取锁然后继续执行。wait(lock, predicate)带谓词判断条件的等待。它等价于while(!predicate()) { wait(lock); }。强烈推荐使用这种方式因为它可以有效防止“虚假唤醒”即线程在没有收到通知的情况下意外被唤醒。wait_for/wait_until带超时时间的等待防止线程永久阻塞。2. 通知方生产者线程notify_one()随机唤醒一个正在等待该条件变量的线程适用于多个线程处理同类任务的场景如线程池。notify_all()唤醒所有正在等待该条件变量的线程适用于广播某种状态变更如程序退出信号。 经典应用场景最典型的就是生产者-消费者模型消费者线程获取锁检查队列是否为空。如果为空就调用cv.wait()释放锁并休眠等待。生产者线程获取锁向队列中放入数据然后调用cv.notify_one()或cv.notify_all()唤醒正在休眠的消费者线程。通过这种机制线程之间能够安全、高效地进行“等待-通知”的交互避免了资源的无效消耗。cv.wait(…) 到底在干什么cv.wait(lock,[]{return!data_queue.empty()||finished;});if(finisheddata_queue.empty())break;这段代码是多线程编程中消费者线程的核心逻辑通常出现在“生产者-消费者”模型中。它的主要作用是让当前线程在“没有数据可处理”且“任务未结束”时安全地进入休眠等待状态。我们可以把这段代码拆解开来详细理解️cv.wait(...)到底在干什么cv.wait(lock, []{ return !data_queue.empty() || finished; });这一行代码非常精妙它实际上在内部自动完成了一套“原子操作”和“循环检查”自动释放锁并休眠当线程运行到这里如果后面的条件不满足即队列为空且任务没结束它会自动释放传入的lock互斥锁然后让当前线程进入阻塞睡眠状态不再占用 CPU 资源。等待被唤醒线程会一直休眠直到其他线程比如生产者调用了cv.notify_one()或cv.notify_all()来唤醒它。防止“虚假唤醒”的安全检查这是使用带条件Lambda 表达式的wait最重要的原因。线程被唤醒后不会立刻往下执行而是会先重新获取锁然后再次检查Lambda 表达式里的条件!data_queue.empty() || finished是否真的成立了。如果条件依然不满足比如是操作系统导致的意外“虚假唤醒”或者被唤醒后发现队列还是空的它会继续释放锁并再次进入休眠。只有当条件真正满足时队列里有数据了或者收到了结束信号wait函数才会正式返回程序继续往下走。 条件!data_queue.empty() || finished的含义这个 Lambda 表达式规定了线程结束等待、继续工作的两个条件满足其一即可!data_queue.empty()数据队列不为空说明生产者已经生产了数据消费者可以起来干活消费数据了。finished这是一个全局的结束标志通常在程序退出或生产结束时被设为true。即使队列是空的只要收到了结束信号线程也必须醒来准备退出防止因为队列一直为空而永远死等下去。 后续的if判断是在做什么当cv.wait成功返回后线程已经拿到了锁并且确认了“要么有数据要么该结束了”。接下来的代码就是做具体的分流处理if(finisheddata_queue.empty())break;这是一个退出判断。如果线程醒来是因为收到了结束信号finished true并且此时队列里的剩余数据也都处理完了data_queue.empty()那么消费者线程就会执行break跳出循环安全地结束自己的生命。总结一下这整段代码就像是一个尽职尽责的工人消费者线程他在休息室里睡觉wait阻塞。只有在“有活干了队列有数据”或者“老板喊下班了finished”的时候才会被叫醒。醒来后如果发现是下班时间且没活干了他就直接打卡回家break否则他就去处理手头的任务。补充当线程收到“队列不为空”或“结束”的信号被唤醒后它并不是立刻、无缝地往下执行的。在cv.wait返回、程序继续往下走之前线程必须重新把刚才释放的那把锁给抢回来重新加锁。所以完整的微观过程其实是这样的释放锁并睡眠程序运行到cv.wait发现条件不满足自动释放锁线程进入休眠。被唤醒收到了通知信号或者发生了虚假唤醒。重新抢锁线程醒来后会尝试重新获取锁。如果此时其他线程比如正在往里塞数据的生产者还占着这把锁刚醒来的线程就得在cv.wait内部再次阻塞等待直到成功把锁抢到手。检查条件抢到锁后cv.wait内部会再次检查!data_queue.empty() || finished这个条件。如果条件真的满足了cv.wait才会正式返回。继续执行程序往下走此时线程是持有锁的状态可以安全地处理队列里的数据或执行退出逻辑。为什么要这么设计因为如果不重新加锁线程醒来往下执行时其他线程可能正好也在操作这个共享队列就会引发数据冲突。cv.wait保证了一旦它返回你的线程一定是拿着锁的这样你后续处理数据就是绝对线程安全的。这就是一个“释放锁 - 睡觉 - 被叫醒 - 拿回锁 - 干活”的精准闭环。使用花括号 {} 来人为限制锁的作用域// 消费者voidconsumer(){while(true){std::unique_lockstd::mutexlock(mtx);// wait 会原子地释放锁并进入等待被唤醒后重新加锁cv.wait(lock,[]{return!data_queue.empty()||finished;});if(finisheddata_queue.empty())break;intdatadata_queue.front();std::cout拿到了数据: datastd::endl;data_queue.pop();lock.unlock();// 处理数据时释放锁std::cout消费了数据: datastd::endl;}}在这个特定的代码逻辑里lock.unlock()是非常有必要的。这主要涉及到多线程编程中的**“锁粒度”和“并发性能”**问题。我们可以从以下两个角度来理解1. 避免浪费性能核心原因std::cout向控制台打印输出是一个相对非常耗时的 I/O 操作。如果不手动unlock()由于你使用了std::unique_lock锁会一直持有到当前的while循环结束即作用域结束unique_lock析构时自动释放。这意味着当线程在慢吞吞地执行两次std::cout打印时它依然死死地攥着mtx这把锁。带来的后果在打印的这段时间里其他线程比如正在拼命生产数据的生产者线程或者其他消费者线程如果想要访问data_queue或mtx就会被强制阻塞只能干等着。这会把原本可以并行工作的多线程程序强行变成“串行”执行严重拖慢整体效率。手动unlock()的好处当你把数据从队列里pop出来之后对共享队列的操作就已经结束了。此时立刻手动释放锁其他线程就能马上获取锁去处理队列里的其他任务而你的线程则可以安心地去打印日志互不干扰。2. 配合unique_lock的灵活性这正是 C 中使用std::unique_lock而不是std::lock_guard的核心优势之一。std::lock_guard只能在作用域结束时自动释放锁非常死板。std::unique_lock允许你在作用域内灵活地手动unlock()和lock()。在这个场景下这种灵活性就是为了尽早释放锁缩小临界区Critical Section的范围。 补充一个最佳实践虽然在这里手动unlock()是完全正确且必要的但在更复杂的业务逻辑中为了防止因为代码分支太多而忘记释放锁C 程序员通常会使用花括号{}来人为限制锁的作用域。例如while(true){intdata;// 用花括号把需要锁的代码包起来{std::unique_lockstd::mutexlock(mtx);cv.wait(lock,[]{return!data_queue.empty()||finished;});if(finisheddata_queue.empty())break;datadata_queue.front();data_queue.pop();// 出了这个花括号lock 自动析构锁自动释放完全不用担心忘记 unlock}// 这里的打印操作不再持有锁其他线程可以并发工作std::cout拿到了数据: datastd::endl;std::cout消费了数据: datastd::endl;}这种写法既保证了尽早释放锁又利用了 RAII 机制资源获取即初始化防止死锁是实际开发中更推荐的写法。

相关文章:

C++ 条件变量 condition_variable

<condition_variable> 是 C 标准库中用于多线程同步的核心头文件。它主要提供了条件变量&#xff08;Condition Variable&#xff09;机制&#xff0c;用来协调多个线程的执行顺序。 简单来说&#xff0c;它的作用就是让一个或多个线程在特定条件不满足时进入休眠&#x…...

LangForce方法:强化VLA模型语言依赖,提升分布外泛化能力并保留语言核心功能

LangForce方法&#xff1a;强化VLA模型语言依赖&#xff0c;提升分布外泛化能力并保留语言核心功能当前VLA模型常依赖视觉线索而非语言指令&#xff0c;在新场景下表现不佳。论文提出的LangForce方法&#xff0c;通过引入对数似然比损失&#xff0c;强化模型对语言的依赖&#…...

【Twitter算法适配型Prompt库】:2024Q2官方推荐权重结构解析+ChatGPT生成内容通过率提升67%的12个黄金句式

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;Twitter算法适配型Prompt库的演进逻辑与2024Q2权重变革本质 算法信号层重构驱动Prompt范式迁移 2024年第二季度&#xff0c;X&#xff08;原Twitter&#xff09;平台正式将Engagement Velocity Ratio&…...

1.8.2 掌握Scala类与对象 - 单例对象与伴生对象

本次实战通过三个案例深入解析了 Scala 中 object 的核心机制&#xff0c;展示了其如何替代 Java 的 static 关键字。首先&#xff0c;通过 MathUtils 定义了存放常量与工具方法的独立单例对象&#xff1b;其次&#xff0c;利用 Person 类与其同名对象演示了“伴生对象”特性&a…...

客户总问案件进度?知识产权自助查询系统让咨询量直降 80%

做知产代理的伙伴一定深有体会&#xff1a;客服每天大半时间都在回复 **“案件到哪一步了&#xff1f;”“历史文件发我一下”“去年委托的案子状态是什么”**&#xff1b;找历史文档要翻遍聊天记录、文件夹&#xff0c;耗时又尴尬&#xff1b;高频次沟通占用大量人力&#xff…...

Python 爬虫进阶技巧:请求头 UA 随机伪装绕过基础检测

前言 当下绝大多数网站均部署了基础反爬检测机制,服务器会优先校验客户端请求身份标识,未携带合法浏览器标识、使用默认程序请求载体的爬虫请求,极易被直接拦截、封禁 IP、返回空数据或跳转拦截页面。爬虫默认发起请求时会自带程序原生 UA 标识,服务器可通过该标识直接识别…...

1.8.1 掌握Scala类与对象 - Scala类

本次实战通过两组对比鲜明的案例&#xff0c;带你快速入门Scala面向对象编程的核心。首先&#xff0c;通过创建User类&#xff0c;我们掌握了Scala普通类的定义方式&#xff0c;了解了如何使用private修饰符封装成员变量&#xff0c;以及如何通过new关键字实例化对象并调用其公…...

别再只会用ActivePart了!CATIA二次开发中,如何用C#递归遍历任意复杂结构树?

CATIA二次开发进阶&#xff1a;用C#递归算法征服任意复杂装配树 在CATIA二次开发领域&#xff0c;ActivePart就像新手司机的自动挡——简单易用却限制重重。当面对包含数百个零件的飞机发动机装配体&#xff0c;或是横跨多个产品的汽车底盘系统时&#xff0c;仅能操作当前激活零…...

2026AI大模型接口聚合站榜单揭晓!这些平台助你一站式解决模型调用难题

跨国网络延迟、复杂的支付方式以及分散的接口协议&#xff0c;常常让开发者在调用AI大模型API时体验不佳。而AI大模型接口聚合站就像一个智能中转平台&#xff0c;能让调用AI大模型API变得像调用本地服务一样简单。通过API聚合站&#xff0c;开发者可以一站式解决国内外主流AI模…...

在线音视频处理工具实测对比:视频压缩、格式转换、音频提取哪家强?

一、为什么要关注在线音视频工具&#xff1f;先看一组数据。根据多家市场研究机构的报告&#xff0c;全球视频处理相关市场规模近年来持续增长&#xff0c;视频内容的生产量每年都在翻倍。各大平台每天新增的视频播放时长以亿计——这意味着越来越多的普通用户和创作者&#xf…...

终极指南:用ContextMenuManager彻底解决Windows右键菜单混乱问题

终极指南&#xff1a;用ContextMenuManager彻底解决Windows右键菜单混乱问题 【免费下载链接】ContextMenuManager &#x1f5b1;️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 你是否曾因Windows右键菜单过于臃肿…...

在VS Code中结合Taotoken实现稳定的AI编程辅助体验

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 在VS Code中结合Taotoken实现稳定的AI编程辅助体验 对于日常使用VS Code进行开发的程序员而言&#xff0c;一个稳定、不间断的AI编…...

Angular 17与Firebase全栈实战:从零构建现代化Web应用

1. 项目概述&#xff1a;一个基于 Angular 17 的现代化 Web 应用最近接手并重构了一个名为 Ditectrev 的 Web 项目&#xff0c;它本质上是一个功能性的前端应用&#xff0c;旨在解决特定领域的信息展示与交互需求。这个项目最初由 Angular CLI 17.3.17 生成&#xff0c;但原始的…...

香港科技大学(广州)的研究者如何让AI记忆力翻倍

这项由香港科技大学&#xff08;广州&#xff09;主导的研究成果发表于2026年第43届国际机器学习大会&#xff08;ICML 2026&#xff09;&#xff0c;会议地点为韩国首尔&#xff0c;论文收录于PMLR第306卷。论文预印本编号为arXiv:2605.05838&#xff0c;有兴趣深入了解的读者…...

【粉丝福利社】三维重建技术与实践:基于NeRF与3DGS

&#x1f48e;【行业认证权威头衔】 ✔ 华为云天团核心成员&#xff1a;特约编辑/云享专家/开发者专家/产品云测专家 ✔ 开发者社区全满贯&#xff1a;CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主 ✔ 技术生态共建先锋&am…...

苹果与伊利诺伊大学:四步AI绘图实现媲美五十步生成质量能力提升

这项由苹果公司&#xff08;Apple&#xff09;与伊利诺伊大学香槟分校&#xff08;UIUC&#xff09;联合开展的研究&#xff0c;于2026年5月以预印本形式发布在arXiv平台&#xff0c;论文编号为arXiv:2605.08078。研究提出了一种名为"正则化轨迹模型"&#xff08;Nor…...

多Agent协作是趋势,但谁来管这些Agent

如果你最近参加过AI相关的技术沙龙或者行业峰会&#xff0c;大概率会听到一个词&#xff1a;多Agent协作。简单说就是&#xff0c;不是一个AI帮你干完所有事&#xff0c;而是多个AI各司其职、互相配合。比如一个Agent负责理解需求&#xff0c;一个Agent负责写代码&#xff0c;一…...

设计器模版底图,一直渲染错误,是因为第一张图变形后内存中图片数据被改了,其他尺码一直错误

这其实是你们现在更需要的组合&#xff1a;不是只看 decode()&#xff0c;而是再确认“这次 decode 对应的还是当前这张图”。再确认“这次 decode 对应的还是当前这张图” 是怎么做到的&#xff0c;详细列举代码我直接从现在这次改动的代码里&#xff0c;把"确认图片身份…...

3分钟掌握RPG Maker资源解密:纯前端工具轻松破解加密文件

3分钟掌握RPG Maker资源解密&#xff1a;纯前端工具轻松破解加密文件 【免费下载链接】RPG-Maker-MV-Decrypter You can decrypt RPG-Maker-MV Resource Files with this project ~ If you dont wanna download it, you can use the Script on my HP: 项目地址: https://gitc…...

本地部署9B代码智能体:基于vLLM与CoPaw-Flash的实践与深度评估

1. 项目概述&#xff1a;在本地部署与评估一个9B参数的代码智能体最近在折腾一个挺有意思的项目&#xff0c;尝试在单张NVIDIA H100 GPU上&#xff0c;部署并评估一个名为CoPaw-Flash-9B的本地代码智能体。这个模型基于Qwen3.5-9B微调而来&#xff0c;专门针对自主智能体任务进…...

Multi-Agent 落地常见问题:数据质量、模型适配与业务对齐解决方案

Multi-Agent 落地常见问题:数据质量、模型适配与业务对齐解决方案 引言 痛点引入:从「演示天堂」到「生产地狱」的Multi-Agent鸿沟 2023年11月OpenAI DevDay发布的GPT-4o Assistants API、LangChain团队迭代的LangGraph 1.0、Microsoft Research推出的AutoGen Studio 2.0,…...

BilibiliVideoDownload跨平台视频下载工具:从安装到高级配置的完整指南

BilibiliVideoDownload跨平台视频下载工具&#xff1a;从安装到高级配置的完整指南 【免费下载链接】BilibiliVideoDownload Cross-platform download bilibili video desktop software, support windows, macOS, Linux 项目地址: https://gitcode.com/gh_mirrors/bi/Bilibil…...

全栈开发新范式:Vibe-Stack集成技术栈实战解析

1. 项目概述与核心价值 最近在探索全栈开发的新范式时&#xff0c;我注意到了 pastropsucez/vibe-stack 这个项目。乍一看这个名字&#xff0c;你可能会觉得有点“玄学”&#xff0c;但深入探究后&#xff0c;我发现它其实是一个高度集成、开箱即用的现代Web应用开发栈。简单…...

如何让老旧安卓电视焕发新生:mytv-android实现流畅播放体验的完整指南

如何让老旧安卓电视焕发新生&#xff1a;mytv-android实现流畅播放体验的完整指南 【免费下载链接】mytv-android 使用Android原生开发的视频播放软件 项目地址: https://gitcode.com/gh_mirrors/my/mytv-android 你是否还在为家中那台反应迟钝、启动缓慢的旧电视而烦恼…...

BIThesis:让北京理工大学论文排版从烦恼变轻松的智能解决方案

BIThesis&#xff1a;让北京理工大学论文排版从烦恼变轻松的智能解决方案 【免费下载链接】BIThesis &#x1f4d6; 北京理工大学非官方 LaTeX 模板集合&#xff0c;包含本科、研究生毕业设计模板及更多。&#x1f389; &#xff08;更多文档请访问 wiki 和 release 中的手册&a…...

斯坦福CS229机器学习中文教程:从零到一的实战学习指南

斯坦福CS229机器学习中文教程&#xff1a;从零到一的实战学习指南 【免费下载链接】Stanford-CS-229 A Chinese Translation of Stanford CS229 notes 斯坦福机器学习CS229课程讲义的中文翻译 项目地址: https://gitcode.com/gh_mirrors/st/Stanford-CS-229 你是否曾因英…...

终极IDM试用重置指南:三步实现无限续期的免费解决方案

终极IDM试用重置指南&#xff1a;三步实现无限续期的免费解决方案 【免费下载链接】idm-trial-reset Use IDM forever without cracking 项目地址: https://gitcode.com/gh_mirrors/id/idm-trial-reset IDM Trial Reset是一款专为Internet Download Manager用户设计的实…...

RevokeMsgPatcher终极指南:3分钟实现微信/QQ/TIM永久防撤回

RevokeMsgPatcher终极指南&#xff1a;3分钟实现微信/QQ/TIM永久防撤回 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁&#xff08;我已经看到了&#xff0c;撤回也没用了&#xff09; 项目地址: https://gitco…...

ikhono开源框架:AI应用开发的统一抽象与实战指南

1. 项目概述与核心价值最近在AI应用开发圈子里&#xff0c;一个名为ikhono-ai/ikhono的开源项目引起了我的注意。乍一看这个标题&#xff0c;你可能会有点懵&#xff0c;这名字不像我们常见的那些“XX-GPT”、“XX-Agent”那么直白。但恰恰是这种独特的命名&#xff0c;让我产生…...

从收音机到5G:OFDM技术的前世今生,以及它为何成为Wi-Fi和5GNR的基石

从收音机到5G&#xff1a;OFDM技术的前世今生&#xff0c;以及它为何成为Wi-Fi和5GNR的基石 想象一下&#xff0c;你正用手机流畅播放4K视频&#xff0c;同时下载大文件——这背后是一套诞生于上世纪60年代的技术在支撑。OFDM&#xff08;正交频分复用&#xff09;的传奇之处在…...