0

0

C++怎么实现协程_C++异步控制教程【前沿】

穿越時空

穿越時空

发布时间:2026-02-27 13:35:02

|

195人浏览过

|

来源于php中文网

原创

c++20协程是编译器级特性,需用co_await/co_yield/co_return声明,返回满足promise_type要求的类型,并提供await_ready/suspend/resume三函数才能被co_await;std::coroutine_handle非线程安全,需谨慎管理生命周期。

c++怎么实现协程_c++异步控制教程【前沿】

协程在 C++20 里不是“实现出来”的,是用 co_awaitco_yieldco_return 写出来的

标准协程不是库函数,也不是你手动写调度器就能“实现”的。C++20 协程是编译器级支持:你写带 co_await 的函数,编译器自动生成状态机和挂起/恢复逻辑。想“手撸协程”?那是 C++17 或更早的 hack(比如 Boost.Coroutine2),但那不是标准协程,也不兼容 std::coroutine_handle

常见错误现象:error: use of undeclared identifier 'co_await' —— 没开 C++20 标准,或没加 -std=c++20(Clang/GCC)或 /std:c++20(MSVC)。

  • 必须返回一个满足 promise_type 要求的类型(如 std::futuretask<t></t> 自定义类)
  • 函数体里至少出现一次 co_awaitco_yieldco_return,否则编译器不视为协程
  • 不能在普通函数里直接 co_await;必须在协程函数内,且被 awaitable 类型支持

怎么让一个类型能被 co_await?关键看它有没有 await_readyawait_suspendawait_resume

不是所有对象都能 co_await。编译器遇到 co_await expr,会按顺序查:expr.operator co_await()operator co_await(expr) → 如果 expr 是类类型,查它是否有这三个成员函数。

使用场景:封装异步 I/O、定时器、线程池任务提交等。比如你想 co_await sleep_for(1s),就得让 sleep_for 返回的对象提供上述三函数。

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

XYZ SCIENCE
XYZ SCIENCE

免费论文AIGC检测,一键改写降AI率

下载
  • await_ready() 返回 bool:立刻完成就返回 true,跳过挂起
  • await_suspend(handle) 接收 std::coroutine_handle:你要在这里决定“挂起后去哪”,比如投递到线程池、注册到 epoll、或直接 resume(即同步执行)
  • await_resume() 返回协程继续执行时拿到的值,可带异常传播

std::coroutine_handle 不是线程安全的,别在线程间裸传

它只是一个轻量指针(通常 8 字节),指向协程帧(coroutine frame)。它的 resume()destroy() 必须由持有方确保不并发调用,否则 UB。

性能影响:频繁跨线程 resume 会导致缓存行失效、虚假共享,比单纯传递数据代价高得多。

  • 如果要从其他线程唤醒协程,务必用原子操作或锁保护 handle 生命周期(比如用 std::shared_ptr 包一层,或用 std::atomic<:coroutine_handle>></:coroutine_handle> 存储)
  • 调用 resume() 后,该 handle 不再有效(除非你显式 copy);调用 destroy() 后,整个协程帧释放,不能再 resume
  • MSVC 下 debug 模式可能额外检查 handle 是否已 destroy,release 模式则完全不检查 —— 容易漏掉 double-resume

别指望协程自动解决线程安全问题

协程切换不等于线程切换。co_await 可能在同一线程上恢复(比如基于 event loop 的 async/await),也可能切到别的线程(比如线程池调度)。协程本身不提供互斥、内存序或生命周期管理。

容易踩的坑:co_await 之后继续访问局部变量没问题,但访问堆对象、全局变量、this 指针所指内容时,必须确认它们的生命周期覆盖整个协程执行期。

  • 不要在协程里 co_await 一个正在析构的对象的 awaitable
  • lambda 捕获局部变量后生成协程,要注意该 lambda 是否逃逸出作用域
  • std::shared_ptr<t></t> 管理跨 co_await 边界的对象,比裸指针靠谱得多

协程帧的分配方式(栈 or 堆)、销毁时机、异常传播路径,都依赖 promise_type 实现。标准库没提供开箱即用的通用协程类型,std::generator(C++23)只读、std::task 还没进标准 —— 得自己搭,或者用 libunifex、cppcoro 等第三方库。写错 promise_type 的 suspend logic,协程就卡死或崩溃,而且调试极难定位。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

391

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

348

2023.10.25

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

87

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

103

2025.09.18

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

87

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

103

2025.09.18

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

294

2025.08.29

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

105

2025.10.23

漫蛙app官网链接入口
漫蛙app官网链接入口

漫蛙App官网提供多条稳定入口,包括 https://manwa.me、https

40

2026.02.27

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 10.3万人学习

C 教程
C 教程

共75课时 | 5万人学习

C++教程
C++教程

共115课时 | 19.5万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号