C++20协程是可扩展底层框架,非开箱即用的async/await;必须正确定义promise_type三要素,co_await按序查找awaiter,跨线程唤醒需通过任务队列投递handle,std::generator不支持异步IO。
标准 C++20 协程不是“实现协程机制”的工具,而是提供了一套可扩展的底层协程框架——它不直接给你 async/await 语义,也不自带调度器或线程池。你必须自己实现 promise_type、coroutine_handle 管理
逻辑和挂起点行为,否则编译器只生成一堆无法运行的骨架代码。
co_await 编译通过却运行崩溃?最常见原因是未正确定义 promise_type 中的 get_return_object()、initial_suspend() 和 unhandled_exception()。C++20 要求这三者必须存在且签名正确,缺一即导致未定义行为(如空指针解引用、栈破坏)。
get_return_object() 必须返回一个能持有 coroutine_handle 的对象(如自定义 Task 类),不能只返回 void 或裸 handleinitial_suspend() 若返回 suspend_always{},但后续没调用 handle.resume(),协程就永远卡住;若返回 suspend_never{},则需确保 promise 构造完成前不发生异常unhandled_exception() 不实现会导致异常穿透栈帧,直接 std::terminate()
co_await 表达式背后真正调用了哪些函数?对任意表达式 expr 执行 co_await expr,编译器按顺序尝试查找并调用:
expr 自身有 operator co_await() 成员函数,调用它,得到 awaiter 对象operator co_await(expr) 非成员重载,调用它expr 作为 awaiter(要求它具备 await_ready() / await_suspend() / await_resume() 三个成员)注意:await_suspend() 返回 void 表示同步恢复;返回 bool 表示是否已自行调度(true = 不恢复,false = 立即恢复);返回 coroutine_handle 则将控制权转交给该 handle。
std::coroutine_handle 安全跨线程唤醒协程?协程挂起后,其栈帧通常位于当前线程栈上(除非用了堆分配的 promise),因此 coroutine_handle::resume() 必须在**同一栈上下文**中调用,否则触发未定义行为。安全跨线程唤醒的唯一合规路径是:
await_suspend() 中获取目标线程的事件循环句柄(如 io_context、自定义任务队列)coroutine_handle 包装成任务对象,投递到目标线程的任务队列handle.resume()
切勿在线程 A 中保存 handle,然后在线程 B 中直接调用 resume()——即使加锁也无效,这是栈生命周期问题,不是竞态问题。
std::generator 直接写异步 HTTP 请求?std::generator 是为同步迭代器场景设计的:它隐含假设每次 co_yield 后立即被消费者调用 next(),且整个生命周期单线程、无挂起等待。它没有 co_await 支持,不能等待文件描述符就绪、不能交出控制权给 IO 多路复用器。试图强行混用会导致:
generator 对象析构时自动调用 destroy(),可能中断正在进行的网络读写co_yield 前插入非阻塞等待逻辑(如 epoll_wait)真要写异步 HTTP,得从零实现一个带 IO 调度能力的 Task 类型,其中 promise_type 内聚了 epoll/kqueue/IOCP 封装和超时管理——这才是 C++20 协程的真实使用姿势。