std::stop_source提供零开销协作式中断机制:主线程调用request_stop()后,生产者及时刷新并退出,消费者清空缓冲区再退出,最后join线程确保安全终止。

在C++20协程与多线程混合的生产者-消费者模型中,当主线程需中断正在批量生成数据的生产者、同时让消费者安全清空缓冲区并退出时,std::stop_source提供了一种无需轮询、不依赖标志位、且能自动通知关联stop_token的零开销终止机制。
初始化可协作中断的生产者与消费者线程
第一步:声明全局或作用域内的std::stop_source对象,它将作为整个任务组的中断信号源。
第二步:将stop_source.get_token()分别传入生产者和消费者的启动函数——注意必须在构造线程前获取token,【一旦线程开始运行,再传递新token无法影响已启动线程的stop_callback注册】。
第三步:在生产者线程函数内部,用while (token.stop_requested() == false)包裹主循环;消费者同理,但需额外检查缓冲区是否为空且token已请求停止,避免死等。
让生产者主动响应中断并完成最后一项工作
方法一:在生产者循环末尾插入if (token.stop_requested()) { flush_remaining_batch(); break; }——这确保即使中断发生在批量写入中途,也能把当前未提交的数据推入队列。
方法二:更稳妥的做法是在每次向共享队列push前先调用token.stop_requested(),若为true则跳过push、直接break。否则可能因队列满而阻塞,导致无法及时响应中断。
方法三:对关键资源(如文件句柄、网络连接)使用RAII包装器,在其析构函数中检查token状态;若已被请求停止,则跳过flush或close操作,防止在中断路径上触发异常。
让消费者优雅退出而不丢弃未处理项
消费者不能一看到stop_requested就立刻return。它必须持续从队列pop直到empty()返回true,【否则残留数据会永远滞留在缓冲区,造成资源泄漏或逻辑错误】。
使用std::unique_lock<:mutex> lock{mtx}配合条件变量wait_for,并在wait的谓词中同时判断(!queue.empty() || token.stop_requested())——这样既不会错过新数据,也不会在中断后无限等待。
当token.stop_requested()为true且queue.empty()也为true时,执行final_cleanup()并退出循环。
主线程触发终止并等待所有线程结束
1、调用stop_source.request_stop()——这是唯一需要显式调用的终止入口,所有关联token都会立即感知。
2、依次调用生产者线程对象的join()→消费者线程对象的join()。注意顺序:先让生产者停,再等消费者清空,否则可能因生产者仍在push导致消费者永远无法满足empty()条件。
3、无需手动重置stop_source或清理token;它们是轻量值类型,离开作用域即销毁。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











