讲师中心 微信公众号
AI工具推荐 视频效率加速

c++20的std::stop_token和std::jthread如何优雅地中断线程? (协作式取消)

星敏同学_9177

星敏同学_9177

发布时间:2026-01-15 15:03:30

|

329人浏览过

|

来源于php中文网

原创

std::jthread构造时自动绑定stop_token,线程函数直接接收std::stop_token参数即可;析构时自动request_stop()并join(),但需线程函数主动轮询stop_requested()以响应取消。

c++20的std::stop_token和std::jthread如何优雅地中断线程? (协作式取消)

std::jthread 构造时自动绑定 stop_token,无需手动传递

std::jthread 在构造时会自动生成一个 std::stop_source,并把对应的 std::stop_token 传给线程函数——这是它比 std::thread 更“优雅”的起点。你不用显式创建 std::stop_source,也不用担心忘记把 token 传进去。

常见错误是仍像用 std::thread 那样手动管理 token,结果重复构造或丢失绑定:

  • 误写 std::jthread t{[](std::stop_token){});:虽然能编译,但丢掉了自动绑定的语义,token 实际来自 jthread 内部,不是你传的那个
  • 试图在构造后调用 t.get_stop_source().request_stop() 前,先用 t.get_stop_token() 去轮询——可行,但没必要,因为线程函数已天然持有有效 token

正确做法就是直接让线程函数接受 std::stop_token 参数:

std::jthread t{[](std::stop_token st) {
    while (!st.stop_requested()) {
        // 做工作...
        std::this_thread::sleep_for(100ms);
    }
    // 自动调用 request_stop() 并 join()
}};

在循环中用 stop_token::stop_requested() 检查取消请求

std::stop_token::stop_requested() 是轻量、无锁、线程安全的检查方式,适合高频轮询。它不阻塞,也不抛异常,只返回 bool,符合协作式取消“主动让出”的设计哲学。

立即学习“C++免费学习笔记(深入)”;

注意几个关键点:

  • 不要用 st.stop_possible() 判断是否能取消——它只表示 token 是否关联了 source,几乎总是 true,对逻辑无实质帮助
  • 避免在 long-running 系统调用(如 read(), accept())中只靠 stop_requested() 轮询,会造成 busy-wait;应配合可中断的等待机制(见下一条)
  • 如果线程正在等待某个条件变量,需在 wait 或 wait_for 中传入 token,否则可能错过取消信号

例如,用 std::condition_variable::wait_until + std::stop_token 实现可中断等待:

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
std::jthread t{[](std::stop_token st) {
    std::mutex m;
    std::condition_variable cv;
    bool ready = false;

    std::unique_lock<std::mutex> lk{m};
    while (!ready && !st.stop_requested()) {
        if (cv.wait_until(lk, std::chrono::steady_clock::now() + 1s, [&]{ return ready; })) {
            break;
        }
    }
}};

std::jthread 析构时自动 request_stop() + join(),但需确保线程函数响应 token

这是 std::jthread 最省心的特性:离开作用域时,它会自动调用内部 stop_source.request_stop(),然后阻塞等待线程退出。但前提是——你的线程函数必须定期检查 stop_token,否则它会永远卡在某处,导致析构 hang 住。

典型陷阱:

  • 线程函数里没检查 token,或者只在循环开头检查一次,之后就进入不可中断的长耗时操作(如大数组排序、文件读取)
  • 使用了不支持 cancellation 的第三方库调用(如某些 C 风格网络 API),且未设超时或封装中断逻辑
  • 在持有锁时长时间等待,而锁未被设计为可被中断

解决思路不是“避免析构”,而是把取消点拆得足够细。例如,在处理大量数据时插入检查:

std::jthread t{[](std::stop_token st) {
    for (int i = 0; i < 1000000; ++i) {
        process_item(i);
        if ((i % 1000 == 0) && st.stop_requested()) {
            break;
        }
    }
}};

需要外部触发取消?用 get_stop_source() 获取可写句柄

当线程启动后,你想从其他地方(比如主线程、信号处理器、UI 事件)主动请求停止,就得拿到它的 std::stop_source。jthread 提供 get_stop_source() 成员函数,返回一个可拷贝、可移动的句柄。

注意事项:

  • get_stop_source() 返回的是副本,调用 request_stop() 是线程安全的,但多次调用无副作用(只会生效第一次)
  • 不能跨线程保存 std::stop_token 后再拿去调用 request_stop()——token 只读,只有 source 才能发起请求
  • 如果你需要多个线程监听同一取消信号,应共享同一个 std::stop_source,而非多个 jthread 各自独立

示例:主线程在特定条件下提前终止工作线程:

std::jthread worker{[](std::stop_token st) {
    while (!st.stop_requested()) {
        do_work();
        std::this_thread::sleep_for(50ms);
    }
}};

// ... 一段时间后
if (some_condition) {
    worker.get_stop_source().request_stop(); // 安全,非阻塞
}
协作式取消真正难的不是 API 调用,而是在线程执行路径的关键节点插入恰当的检查点——尤其是那些看似“短暂”实则可能因数据规模或系统负载而变长的操作。token 本身不会中断任何东西,它只提供一个“该停了”的信号;谁来响应、何时响应、响应后如何清理,全在你自己手里。

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

超级麦吉

一款通过数字员工协作完成调研、数据分析与文档制作的AI办公平台。

花生AI
花生AI Hot

一款AI视频创作工具,主要用于B站推出的AI视频创作工具,适合需要提升相关任务效率的用户。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

相关专题

更多
登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

14466

2023.09.14

登录token无效怎么办
登录token无效怎么办

登录token无效的解决办法有检查Token是否过期、检查Token是否正确、检查Token是否被篡改、检查Token是否与用户匹配、清除缓存或Cookie、检查网络连接和服务器状态、重新登录或请求新的Token、联系技术支持或开发人员等。本专题为大家提供token相关的文章、下载、课程内容,供大家免费下载体验。

1705

2023.09.14

token怎么获取
token怎么获取

获取token值的方法:1、小程序调用“wx.login()”获取 临时登录凭证code,并回传到开发者服务器;2、开发者服务器以code换取,用户唯一标识openid和会话密钥“session_key”。想了解更详细的内容,可以阅读本专题下面的文章。

3997

2023.12.21

token什么意思
token什么意思

token是一种用于表示用户权限、记录交易信息、支付虚拟货币的数字货币。可以用来在特定的网络上进行交易,用来购买或出售特定的虚拟货币,也可以用来支付特定的服务费用。想了解更多token什么意思的相关内容可以访问本专题下面的文章。

6161

2024.03.01

登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

14466

2023.09.14

登录token无效怎么办
登录token无效怎么办

登录token无效的解决办法有检查Token是否过期、检查Token是否正确、检查Token是否被篡改、检查Token是否与用户匹配、清除缓存或Cookie、检查网络连接和服务器状态、重新登录或请求新的Token、联系技术支持或开发人员等。本专题为大家提供token相关的文章、下载、课程内容,供大家免费下载体验。

1705

2023.09.14

token怎么获取
token怎么获取

获取token值的方法:1、小程序调用“wx.login()”获取 临时登录凭证code,并回传到开发者服务器;2、开发者服务器以code换取,用户唯一标识openid和会话密钥“session_key”。想了解更详细的内容,可以阅读本专题下面的文章。

3997

2023.12.21

token什么意思
token什么意思

token是一种用于表示用户权限、记录交易信息、支付虚拟货币的数字货币。可以用来在特定的网络上进行交易,用来购买或出售特定的虚拟货币,也可以用来支付特定的服务费用。想了解更多token什么意思的相关内容可以访问本专题下面的文章。

6161

2024.03.01

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

60

2026.10.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
夸克AI浏览器使用手册
夸克AI浏览器使用手册

共0课时 | 0人学习

jQuery官方API文档
jQuery官方API文档

共0课时 | 0人学习

Manus AI 入门手册
Manus AI 入门手册

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn