co_await 触发编译器生成状态机并调用用户定义的awaiter协议方法;必须实现await_ready/await_suspend/await_resume,否则编译报错。

co_await 不是语法糖,它触发编译器生成状态机 + 调用用户定义的 awaiter 协议方法;没实现 await_ready/await_suspend/await_resume 就不能被 co_await,编译直接报错。
co_await 表达式到底做了什么
当你写下 co_await expr,编译器不会直接执行 expr,而是检查 expr 类型是否满足“可等待”(awaitable)要求:必须能通过 ADL 找到 operator co_await,或自身就提供三个成员函数。整个过程分三步走:
- 先调
await_ready()判断是否立刻就绪——返回true就跳过挂起,直接执行await_resume() - 若返回
false,则调await_suspend(coroutine_handle<> h),把当前协程句柄传进去,由你决定怎么调度(比如扔进线程池、注册到 epoll、或直接 resume) - 之后协程暂停,控制权交出;等外部条件满足后,必须显式调用该协程句柄的
resume(),才会再次进入await_resume()并继续往下走
为什么自定义 awaiter 经常漏掉 await_suspend 返回值
await_suspend 的返回类型决定了协程是否自动恢复:
- 返回
void:协程挂起后,不会自动恢复,必须靠外部调用coroutine_handle::resume() - 返回
bool:true表示已安排好恢复(比如投递到事件循环),协程保持挂起;false表示不挂起,立即继续执行(相当于同步路径) - 返回另一个
coroutine_handle<>:表示将当前协程移交(transfer)给那个句柄,原协程直接 resume 目标协程,自己终止
多数人只写 await_suspend 但忽略返回值含义,结果协程“卡住不动”,调试时发现 await_resume 死活不进——其实是 await_suspend 返回 void 后没人调 resume()。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
std::coroutine_handle<> 的生命周期管理是个坑
协程帧(frame)默认堆分配,coroutine_handle 是裸指针语义:
- 它不管理内存,
coroutine_handle::destroy()必须手动调用,否则泄漏 - 一旦调用
destroy(),所有同源句柄都变野指针,再resume()就是未定义行为 - 协程结束后,
promise_type::unhandled_exception()和final_suspend会触发,这里常用来做自动清理——但前提是final_suspend返回suspend_always{},否则协程帧可能在 resume 后立刻被析构
别把 co_await 当成 async/await 那样开箱即用
C++20 协程没有运行时、没有默认调度器、不绑定线程模型:
-
co_await本身不启动线程,也不隐式创建 event loop - 你写的
await_suspend怎么调度,协程就在哪恢复——可能是同一线程延后执行,也可能是另一线程唤醒,全由你控制 - 标准库至今没提供生产级 awaitable(
std::generator是只读的,std::task还在 TS 中),所有实用封装(如 cppcoro、libunifex)都是第三方补位
真正难的从来不是写对三个 awaiter 方法,而是想清楚:这个 awaitable 的生命周期谁管?挂起后谁负责 resume?错误怎么传播?这些逻辑一旦散落在各处,协程就从简化异步变成制造隐式依赖。

















