std::stop_callback 是在 std::stop_source 调用 request_stop() 且对应 std::stop_token 有效时触发的回调,用于协作式取消中的资源清理;它不随线程退出自动执行,需确保其生命周期覆盖停止过程,且回调函数必须 noexcept。

std::stop_callback 是什么,它在什么场景下才生效
std::stop_callback 不是“线程退出时自动触发”的钩子,它只在 std::stop_source 被显式请求停止(调用 request_stop())且对应 std::stop_token 尚未被放弃(未析构、未 move)时执行。它和线程生命周期没有直接绑定——线程可能还在跑,但停止请求已发出;也可能线程已结束,但 stop_callback 从未被调用(因为没人调 request_stop())。
典型适用场景:协作式取消(cooperative cancellation),比如你在循环中定期检查 token.stop_requested(),并在收到请求后主动退出,同时用 std::stop_callback 做清理(如关闭文件句柄、释放锁、注销监听器)。
如何正确构造和持有 std::stop_callback
必须确保 std::stop_callback 对象的生命周期覆盖整个可能的停止过程;一旦它析构,回调就失效,即使后续调用 request_stop() 也不会触发。
- 不能在栈上临时构造后立即离开作用域(例如写成
std::stop_callback{token, []{...}};)——它会立刻析构,回调永远不会执行 - 推荐方式:作为类成员变量持有,或在 lambda 捕获中按值持有(前提是该 lambda 存活时间足够长)
- 注意移动语义:
std::stop_callback可移动但不可复制;move 后原对象进入有效但未指定状态,不能再调用其成员函数
常见错误:回调没执行,但代码看起来没问题
最常踩的坑是 token 和 callback 的生命周期错配,或者误以为线程结束会触发 stop_callback。
立即学习“C++免费学习笔记(深入)”;
-
std::jthread确实会在析构时自动调用request_stop(),但前提是它的std::stop_token还活着,且你构造的std::stop_callback仍存在 —— 如果 callback 是局部变量,它早于 jthread 析构就销毁了 - 忘记检查
token.stop_possible():如果 token 来自已 move 出去的std::stop_source,它可能变成无效状态(stop_possible() == false),此时构造std::stop_callback会抛std::system_error - 回调函数抛异常:C++20 规定,若回调抛出异常,程序将调用
std::terminate()—— 所有回调必须保证 noexcept 或自行捕获异常
一个安全可用的 minimal 示例
下面是在 std::jthread 中配合 std::stop_callback 做资源清理的写法:
<code>void worker(std::stop_token token) {
// 持有 stop_callback 作为局部变量(注意:不能是临时对象)
std::stop_callback cb{token, []{
std::cout << "cleanup: releasing resource\n";
}};
while (!token.stop_requested()) {
std::this_thread::sleep_for(100ms);
}
// token.stop_requested() 为 true 后退出循环
// 此时 cb 仍在作用域内,request_stop() 触发后它会执行
}
int main() {
std::jthread t{worker};
std::this_thread::sleep_for(300ms);
// t 析构时自动 request_stop() → cb 被调用
}
关键点在于:callback 必须比 stop 请求的发起时机“活得久”,且不能依赖线程终止本身来驱动它 —— 它响应的是停止请求,不是线程死亡。


















