C++20:std::stop_source让线程说停就停

发布时间:2026/9/25 20:41:17

C++20:std::stop_source让线程说停就停 std::stop_source是 C20 引入的标准库组件位于stop_token头文件中用于在多线程编程中实现协同式线程取消Cooperative Thread Cancellation。它提供了一种线程安全、优雅且通用的机制用来发起“停止请求”使运行中的异步任务或后台线程能够主动检查并安全退出。背景对比在 C20 之前终止线程通常依赖手动维护std::atomicbool标志位或者使用平台特定的 API如 POSIXpthread_cancel。然而平台强制终止极易导致 RAII 析构函数未运行、互斥锁死锁以及资源泄漏等未定义行为UB。核心协作三元组C20 的协同取消机制由三个相互协作的组件构成std::stop_source信号控制端负责发起停止信号调用.request_stop()。std::stop_token信号观察端传递给工作线程用于轮询或检查是否收到了停止信号调用.stop_requested()。std::stop_callback回调绑定机制允许注册回调函数当停止请求被发起时同步触发用于打断处于阻塞状态的 I/O 或条件变量。一、 API 详解1.std::stop_source核心接口核心控制与 Token 获取**request_stop()-bool**作用发起停止请求。返回值首次成功发起停止请求返回true若此前已发起过停止请求或当前对象未关联有效的底层状态返回false。副作用使所有关联的std::stop_token::stop_requested()返回true并同步触发所有已注册的std::stop_callback。**get_token()-std::stop_token**作用获取与当前stop_source绑定共享状态的std::stop_token对象用于下发给工作线程。状态查询**stop_requested() const-bool**作用检查关联的底层状态是否已收到停止请求。**stop_possible() const-bool**作用检查当前对象是否仍有可能发起停止请求。若关联了有效状态且未被全部释放返回true若为默认构造的空对象或所有关联的stop_source均已销毁返回false。生命周期与比较构造函数stop_source()默认构造创建一个新的可触发停止请求的底层共享状态。stop_source(std::nostopstate_t)构造一个不带底层状态的空对象stop_possible()为false。拷贝 / 移动构造支持拷贝与移动。由于底层使用引用计数管理状态拷贝出的多个stop_source共享同一个底层状态。**swap()/std::swap**交换两个stop_source对象的底层状态。比较运算符 (/!)判断两个stop_source是否共享同一个底层停止状态或均为空。2.std::stop_token核心接口状态查询**stop_requested() const-bool**作用检查关联的std::stop_source是否已发起停止请求。典型用途作为工作线程主循环的退出条件如while (!stoken.stop_requested())。**stop_possible() const-bool**作用检查当前token是否仍有可能收到停止请求。若关联了有效状态且至少存在一个存活的stop_source返回true若所有stop_source均已析构或token本身为无状态对象nostopstate返回false。优化场景在长循环中若stop_possible()为false可提前终止对stop_requested()的无效轮询。生命周期与比较构造函数stop_token()创建不包含底层状态的空 tokenstop_possible()和stop_requested()均返回false。拷贝与移动支持轻量级拷贝与移动多个stop_token可分发至多个并发线程共享同一个状态观察点。swap()与比较运算符 (/!)与stop_source行为一致比较或交换底层共享状态。3.std::stop_source与std::stop_token对比维度std::stop_sourcestd::stop_token角色定义信号控制者控制端信号观察者只读端核心职责发起停止请求request_stop()检查停止状态stop_requested()线程归属通常由主控线程 / 管理线程持有传递给一个或多个后台工作线程接口安全性拥有修改权可改变底层共享状态完全只读无法发起取消天然编译期接口安全生命周期依赖只要存在一个存活的stop_source即可触发取消即使所有stop_source均已析构stop_token仍可安全查询但stop_possible()会变为false二、 代码示例示例 1配合std::thread或异步任务手动控制#includeiostream#includethread#includechrono#includestop_tokenvoidworker(std::stop_token stoken){while(!stoken.stop_requested()){std::coutWorker running...\n;std::this_thread::sleep_for(std::chrono::milliseconds(500));}std::coutWorker received stop request, cleaning up and exiting.\n;}intmain(){std::stop_source source;// 将与其绑定的 stop_token 传给工作线程std::threadt(worker,source.get_token());std::this_thread::sleep_for(std::chrono::seconds(2));// 主线程发起停止请求std::coutMain thread requesting stop...\n;source.request_stop();t.join();return0;}示例 2与std::jthread深度集成自动感知与生命周期绑定C20 的std::jthread内部原生集成了std::stop_source。若可调用对象Task/Function的首个参数类型为std::stop_tokenstd::jthread会自动传入 token并在析构时自动触发request_stop()并执行join()#includeiostream#includethread#includechronovoidworker(std::stop_token stoken){while(!stoken.stop_requested()){std::coutWorking...\n;std::this_thread::sleep_for(std::chrono::milliseconds(300));}std::coutCleaning up...\n;}intmain(){{// t 析构时会自动调用 request_stop() 并 join()std::jthreadt(worker);std::this_thread::sleep_for(std::chrono::seconds(1));// 亦可显式手动发起t.request_stop();}// 超出作用域自动发起停止请求并阻塞等待线程结束return0;}三、 架构亮点与设计哲学1. 读写分离与权责对等Separation of Concerns接口设计严格区分了“控制端”与“执行端”控制端stop_source独占修改权执行端stop_token仅保留只读观察权。这种编译期强化的类型约束彻底杜绝了工作线程误触发取消信号的可能性显著降低了多线程代码的耦合度。2. 协同式安全与无锁高效设计协同非强制区别于 POSIXpthread_cancel等强制终止线程的危险做法该机制强制要求工作线程“主动响应”确保了栈展开Stack Unwinding与 RAII 资源释放的完整性。高效无锁实现底层共享状态建立在原子变量与引用计数之上拷贝与状态检查均无需显式加锁拥有极高的并发性能。3. 解决阻塞响应的“灵魂”std::stop_callback如果仅有轮询stop_requested()当线程处于阻塞如 sleep、网络 I/O、条件变量等待时将无法及时响应。std::stop_callback允许向stop_token注册回调一旦request_stop()被触发回调将立即被调用例如用于中断 Socket 或唤醒条件变量。C20 同步引入了std::condition_variable_any::wait(lock, stoken, pred)彻底解决了“条件变量阻塞等待与取消信号协同”的难题。四、 局限性与设计遗憾踩坑避雷指南1. 无法直接中断系统级/C API 阻塞stop_token本质上是语言层面的状态标记与回调通知机制无法做到操作系统内核级的信号中断Interrupted System Call。风险点若线程阻塞在未封装stop_callback的传统 POSIXread()/select()或 Win32 阻塞 API 中单纯查询stop_token无法唤醒线程。必须在stop_callback中手动执行shutdown(fd)或关闭 Handle 来强制打断。2. 回调函数的同步执行上下文与死锁陷阱极易踩坑stop_callback默认是在调用request_stop()的线程上下文中同步Synchronously执行的。死锁风险若调用request_stop()的线程持有互斥锁 A而stop_callback内部也尝试获取锁 A将直接引发死锁。性能抖动若注册的回调逻辑较为昂贵会直接阻塞调用request_stop()的主控线程。3. 缺乏树状/层级化取消支持Non-Hierarchical标准库的实现是扁平化Flat的。在复杂的任务调度或 Actor 模型中常见的“取消父任务自动取消所有子任务但取消子任务不影响父任务”的层级取消逻辑Hierarchical CancellationC20 原生机制并不支持需要结合图/树结构二次封装。4. 对传统std::condition_variable的兼容性限制由于历史包袱传统的std::condition_variable硬绑定了std::unique_lockstd::mutex。出于 ABI 兼容与性能考虑它无法直接配合stop_token使用。必须切换到通用性更强但开销略高的std::condition_variable_any。
延伸阅读

更多相关文章

2026/9/22 13:33:18

AI驱动的跨平台英语学习系统:用兴趣视频构建个性化学习闭环

这次我们来看一个打通插件、网站和手机APP的完整英语学习系统。它的核心思路不是让你背单词书,而是让你用自己真正喜欢的视频内容来学英语——通过AI技术实现视频内容提取、生词管理、听力练习、口语跟读和复习测试的全流程闭环。如果你厌倦了传统英语学习软件的固定…

2026/9/21 7:13:47

AI记忆卡项目:本地部署与测试指南,打造个性化智能助手

这次我们来看一个能自动收集工作进度的 AI 记忆卡项目。它瞄准的核心痛点很直接:日常工作中,我们经常需要向 AI 助手重复描述项目背景、任务进展和个人偏好,这个过程繁琐且低效。这个项目通过一张“记忆卡”,让 AI 能够自动、持续…

2026/9/21 5:02:49

维修工程师的示波器实战:11 为什么有些问题,一测反而消失了?

第十一篇:为什么有些问题,一测反而消失了? ——当你拿起示波器的那一刻,你已经改变了现场 凌晨一点半。 包装线再次毫无征兆地停机。 通讯超时、PLC报警、EtherCAT从站丢失……五秒后系统又自行恢复。 过程极短,却足以让整条产线瘫痪。 维修团队已连续奋战三天,故障只…

2026/9/25 20:38:29

ssh-copy-id 提示成功,但 Dropbear 仍无法免密登录

一、问题现象开发服务器需要频繁通过 SSH、SCP 连接嵌入式板:ssh rootXXX scp XXX rootXXX:/home/root/app/但每次都需要输入 root 密码,使用很不方便执行公钥安装:ssh-copy-id -i ~/.ssh/id_ed25519.pub rootXXX提示添加成功:Num…

2026/9/25 20:38:29

B树如何优化磁盘IO:从原理到工程实践全解析

前几天处理一份数据库慢查询时,系统日志里蹦出一条磁盘IO重试记录:逻辑块地址0x11d40360处重试IO操作。那条查询走的是主键索引,理论上是三层B树,最多三次磁盘IO就能拿到数据,实际却卡了快两秒。问题最后查出来出在硬件…

2026/9/25 20:38:29

2026年10款靠谱降AI率平台推荐:论文AIGC检测轻松过关

随着知网、维普、万方等主流学术平台对AIGC检测标准不断升级,论文通过率面临严峻挑战。选择一款高效的降AI工具已成为关键突破口。本文将实测对比10款主流工具,为读者提供精准的解决方案参考。为什么需要降 AI 率工具? 2026 年,各…

2026/9/25 20:33:28

企业AI聚合平台选型实录:主流模型聚合方案深度复盘与权重分析

步入 2026 年,企业构建 AI 能力的思路已经变了:不再纠结与单一厂商深度绑定,而是把数十个大模型的 API 整合进统一的接口与账单体系。聚合平台从降本工具演变为支撑生产环境的核心基础设施,高并发产线下对稳定性、合规性、延迟的要求近乎苛刻。本文对活跃度最高的几家平台做一次…

2026/9/24 20:24:47

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/23 12:06:55

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/25 0:02:35

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:02:35

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:02:35

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/25 18:41:36

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/25 18:34:56

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑