std::stop_callback只在request_stop()调用后且对象存活时触发一次,需配合轮询stop_requested()使用;应作为类成员或线程外局部变量声明,避免在lambda内定义,且回调中仅执行轻量无阻塞操作。

std::stop_callback 不负责“取消任务”,只负责“通知已请求取消”;它不中断执行、不抛异常、不等待,注册后最多触发一次,且必须配合主动轮询才能生效。
std::stop_callback 为什么总不触发?
常见现象是调用了 source.request_stop(),但注册的回调函数完全没执行——这通常不是 bug,而是生命周期或绑定时机问题。
-
std::stop_callback对象必须存活到request_stop()被调用之后;局部变量在函数返回时就析构了,回调自然失效 - 若用
std::jthread构造时传入 lambda,而把std::stop_callback声明在 lambda 内部(即函数作用域),它会在 lambda 执行结束时销毁,早于可能发生的取消请求 - token 来源不可靠:比如从已移动走的
std::stop_source拿 token,或捕获了悬空引用 - 没有真正调用
request_stop(),只是设了个标志——std::stop_callback只响应std::stop_source::request_stop(),不响应任意自定义 flag
std::stop_callback 应该放在哪?
它的生命周期必须覆盖“取消请求发出”到“回调执行完毕”的整个窗口。实践中只有两种可靠位置:
- 作为类成员变量:在拥有长期生命周期的对象中持有,例如 task manager 或 async operation wrapper
- 作为线程函数外的局部变量:和
std::jthread或std::thread同级声明,确保它比线程活得久
反例:std::jthread t([&token]{ std::stop_callback cb(token, []{...}); ... }); —— cb 是 lambda 局部变量,线程启动后随时可能析构。
正例:
std::stop_source source;<br>auto token = source.get_token();<br>std::stop_callback cb(token, []{ cleanup(); }); // ✅ 在线程外声明<br>std::jthread t([token]{ while(!token.stop_requested()) { /* work */ } });<br>source.request_stop(); // cb 一定被触发
std::stop_callback 里能做什么?
它适合做轻量、无阻塞、线程安全的收尾动作,比如:
- 关闭裸文件描述符(
close(fd)) - 释放非托管内存(
delete ptr) - 置位原子状态(
done_flag.store(true, std::memory_order_relaxed)) - 唤醒等待线程(
cv.notify_one())
以下操作应避免:
- 调用阻塞 I/O(如
write(),fsync())——会拖慢整个取消路径 - 获取互斥锁(尤其是可能被工作线程持有的锁)——极易死锁
- 调用可能抛异常的函数(
std::stop_callback析构器不处理异常,会 terminate) - 访问已被析构的对象(如 lambda 捕获的栈变量、已 join 的线程句柄)
std::stop_callback 和轮询 stop_requested() 是二选一吗?
不是。它们解决不同问题,常需共存:
-
stop_requested()轮询用于任务主体快速响应,决定“是否继续干活” -
std::stop_callback用于确保“哪怕任务已退出,某些资源仍被清理”——比如异步 I/O handle 必须 cancel,否则内核资源泄漏
典型组合模式:
void io_task(std::stop_token st) {<br> auto handle = start_async_read(st);<br> std::stop_callback cb(st, [=]{ cancel_async_read(handle); }); // 确保 cancel<br> while (!st.stop_requested()) {<br> if (wait_for_completion(handle, 100ms)) break;<br> }<br>}
这里 cb 是兜底保障,轮询是主响应路径。
真正容易被忽略的是:**回调不能替代协作检查点**。即使注册了 std::stop_callback,只要任务主体不检查 stop_requested(),它就会一直跑下去,直到超时、出错或被外部强杀——而这已经脱离了 C++20 协作取消的设计本意。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











