c++oding="utf-8" ?>
std::stop_token是c++20引入的协作式线程取消机制的观察者组件,解决传统强制终止导致资源泄漏和数据竞争的问题,通过让线程主动轮询stop_requested()或使用支持它的阻塞函数(如condition_variable::wait重载)实现优雅退出。

std::stop_token 是什么,它能解决什么问题
std::stop_token 是 C++20 引入的协作式线程取消机制核心组件,不是“强制杀线程”,而是让工作线程主动检查是否该退出。它解决的是 std::thread::join() 前必须确保线程已自然结束的痛点——比如循环中无休止等待、阻塞 I/O 或 sleep 导致无法及时响应退出请求。
常见错误现象:手动用 bool* 或 std::atomic<bool></bool> 控制循环,但若线程卡在 std::this_thread::sleep_for() 或 queue.pop()(无超时)里,stop_requested() 就永远没机会被轮询到。
关键点在于:std::stop_token 本身不触发任何行为,它只是个“查询接口”;真正触发协作退出的是 std::stop_source 的 request_stop(),且必须由线程自己定期检查 stop_token.stop_requested() 或使用带 stop_token 的阻塞函数(如 std::condition_variable::wait() 重载)。
如何正确构造和传递 stop_token 给工作线程
构造顺序和生命周期管理是最大坑点:std::stop_source 必须在线程启动前创建,并通过值或引用传入;std::stop_token 可从 stop_source.get_token() 获取,但不能比 stop_source 先销毁。
推荐做法:
- 在主线程中定义
std::stop_source ss;,然后把ss.get_token()传给线程函数(按值传递安全,因为std::stop_token是可复制的轻量对象) - 线程函数签名建议为
void worker(std::stop_token st),避免裸指针或全局变量 - 不要在线程内重新构造
std::stop_source—— 每个协作退出只应有一个源头 - 如果线程需调用第三方阻塞函数(如
read()),必须配合超时或信号机制,stop_token本身无法中断系统调用
std::thread t([](std::stop_token st) {
while (!st.stop_requested()) {
do_work();
if (st.stop_requested()) break; // 双重检查更稳妥
std::this_thread::sleep_for(100ms);
}
}, ss.get_token());
哪些标准库函数支持 stop_token,怎么用
C++20 起,部分阻塞函数提供了接受 std::stop_token 的重载,它们会在收到停止请求时提前返回(通常抛 std::stop_token::stop_requested() 或返回空结果),避免死等。
目前明确支持的有:
-
std::condition_variable::wait()和wait_for():传入stop_token后,若请求停止,会直接返回而非继续等待 -
std::future::wait_until()和wait_for()(部分实现):行为依标准库而定,libc++ 和 MSVC 已支持,libstdc++ 尚未完全跟进 -
std::jthread构造时自动绑定stop_source,析构时自动request_stop()并join(),是最简方案
注意:std::mutex::lock()、std::queue::pop()、std::cin >> 等**不支持** stop_token —— 它们没有重载版本,也不能被 stop_token 中断。
jthread 比 thread + stop_token 更值得优先用吗
std::jthread 是 C++20 对线程管理的封装增强,内部自带 std::stop_source,构造时自动关联,析构时自动 request_stop() 并 join()。它不是“替代”,而是“简化常用模式”。
适用场景:
- 你希望线程对象离开作用域时自动安全退出并回收 —— 直接用
std::jthread - 你需要多个线程共享同一个停止信号(如一组 worker)—— 还得手管
std::stop_source,jthread每个实例独立 - 你依赖
std::thread的细粒度控制(如分离线程、多次join())——jthread不支持detach()
典型写法:
std::jthread t([](std::stop_token st) {
while (!st.stop_requested()) {
// ... work
std::this_thread::sleep_for(1s);
}
}); // 自动 request_stop() + join()
复杂点在于:stop_token 机制依赖线程主动轮询或使用支持它的阻塞调用;没人能绕过“协作”这个前提。最容易被忽略的是——忘记在长耗时操作前后加 stop_requested() 检查,或者误以为它能中断任意阻塞,结果线程卡住不动。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











