std::stop_token是C++20协作式线程取消机制的查询接口,解决传统volatile bool等手动取消方式的内存序和漏检问题;需配合std::jthread使用,支持共享取消源与stop_callback回调,但要求线程主动轮询stop_requested()。

std::stop_token 是什么,它能解决什么问题
std::stop_token 是 C++20 引入的协作式线程取消机制的核心组件,它本身不“停止”任何东西,只提供一种轻量、无锁的查询接口,让线程主动检查是否被请求停止。它解决的是传统 std::thread 缺乏标准化取消语义的问题——比如靠全局 flag + volatile bool 或 mutex 保护的 bool 变量,既容易漏检,又可能因内存序导致延迟或未定义行为。
- 它必须和
std::jthread配合使用才真正“开箱即用”;单独绑定到普通std::thread需手动管理std::stop_source - 不支持强制终止(如
pthread_cancel),所有逻辑必须是协作式的:线程需定期调用stop_token::stop_requested()或注册回调 - 生命周期安全:
std::jthread析构时自动调用request_stop(),避免资源泄漏或等待死锁
用 std::jthread + stop_token 实现自动关闭
std::jthread 是 std::thread 的现代替代品,自带 std::stop_source,构造时自动关联一个 std::stop_token。这是最简、最安全的用法。
void worker(std::stop_token stoken) {
while (!stoken.stop_requested()) {
// 做工作...
if (/* 某个条件满足 */) break;
std::this_thread::sleep_for(100ms);
}
// 自动清理(如 close fd、flush buffer)
}
<p>int main() {
std::jthread t{worker}; // 自动传入绑定的 stop_token
std::this_thread::sleep_for(500ms);
// t 析构时自动 request_stop(),或显式调用 t.request_stop()
}
</p>
-
std::jthread的析构函数会阻塞等待线程结束,并在等待前调用request_stop() - 如果线程函数参数是
std::stop_token,编译器自动从std::jthread内部提取并传递 - 不要在线程函数里保存
std::stop_token的拷贝去跨函数传递——它 cheap to copy,但语义上应始终代表同一取消源
手动管理 stop_source 和 token 的场景
当你需要多个线程共享同一个取消信号,或想在某个对象生命周期内统一控制一组任务时,就得显式持有 std::stop_source。
class TaskManager {
std::stop_source m_stop_src;
public:
void start() {
std::jthread t{[this](std::stop_token st) {
while (!st.stop_requested()) {
do_work();
std::this_thread::sleep_for(200ms);
}
}, m_stop_src.get_token()};
// 保存 t 或交给成员变量管理
}
<pre class="brush:php;toolbar:false;">void shutdown() {
m_stop_src.request_stop(); // 同时通知所有关联 token
}};
-
std::stop_source可以被拷贝,每个拷贝都指向同一取消状态;std::stop_token同样可拷贝,但只读 - 多个
std::stop_token可来自同一个std::stop_source,适合扇出式任务(fan-out) - 注意:
std::stop_source::request_stop()是幂等的,重复调用无副作用;但一旦调用,所有关联 token 的stop_requested()永远返回 true
stop_callback 的适用时机和陷阱
std::stop_callback 允许你在取消请求发生时立即执行一段逻辑(比如释放独占资源、唤醒等待线程),但它不是“线程入口”,也不替代轮询。
void worker(std::stop_token stoken) {
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
<pre class="brush:php;toolbar:false;">// 注册回调:一旦被 request_stop,立刻 notify
std::stop_callback cb{stoken, [&]{
std::lock_guard<:mutex> lk{mtx};
ready = true;
cv.notify_one();
}};
std::unique_lock<:mutex> lk{mtx};
cv.wait(lk, [&]{ return stoken.stop_requested() || ready; });</:mutex></:mutex>}
- 回调函数在调用
request_stop()的同一线程中同步执行(不是新线程),所以必须快、不能阻塞、不能抛异常 - 它不替代轮询:如果线程正 block 在
read()或std::condition_variable::wait()上,stop_callback能帮你打破阻塞,但你仍需在循环条件里检查stop_requested() - 回调对象生命周期绑定到
std::stop_callback实例,离开作用域自动注销;不要把它存成裸指针或引用
C++20 的协作取消机制不是银弹——它要求你把“可取消性”设计进逻辑路径里,而不是事后打补丁。最容易被忽略的是:没有轮询就没有响应,没有显式检查 stop_requested(),std::stop_token 就只是个哑巴令牌。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











