【知乎】如何编写 C++ 20 协程(Coroutines)
基本概念
Coroutine
Coroutine $:=$ 含有 co_return/co_await/co_yield 的可暂停/唤醒的函数
Coroutine State
包含
- Promise object
 - 函数参数 (copy by value)
 - 当前暂停点の局部变量 local variables and temporaries whose lifetime spans the current suspension point.
 - 当前暂停点の特征信息 some representation of the current suspension point, so that a resume knows where to continue, and a destroy knows what local variables were in scope
 
Coroutine Execution
Coroutines (C++20) # Execution - cppreference.com
协程执行顺序文字版
    
      一个 coroutine 按以下顺序执行:
- 调用 
operator new分配 coroutine state auto promise = return_type::promise_type{ /* ... */ };构造 Promise object 根据return_type::promise_type- 优先选择参数为函数参数の构造函数 - 如果没有,则选用默认构造函数internal_local_val = promise.get_return_object();return_object会在协程第一次暂停时返回给 caller- exception 返回给 caller,promise 不保留 exception
 await promise.inital_suspend();--> suspend_never: eager-started, 立刻开始 --> suspend_always: lazy-started, 等待主动调用coroutine_handle.resume()开始协程- 继续执行函数体
 - 遇到暂停点
 - 执行 三大协程操作 中的两大
 - caller/resumer 得到 
static_cast<return_type>(return_object) - 执行到 
co_return expr; - 执行 
promise.return_xxx()-decltype(expr) == void$\to$ 执行promise.return_void()-decltype(expr) != void$\to$ 执行promise.return_value(expr)-co_return;$\to$promise.return_void() - raii 倒序析构
 promise.final_suspend();--> suspend_never: 立即销毁 --> suspend_always: 等待主动调用coroutine_handle.destroy()销毁协程
 | 
 | 
uncaught exception in coroutine
    
      如果有 uncaught exception,则执行:
 | 
 | 
underfined behaviour 之 falling off end
    
      - falling off end without 
promise.return_void()定义 
 | 
 | 
- falling off end with return_type not 
voidand without co keyword 
- without co keyword $\to$ 不是协程,无论 return_type 是不是 Awaitable
 - falling off end with return_type not 
void$\to$ 普通函数的 ub 
 | 
 | 
dangling reference 之 协程 copy by value 传引用
    
      todo
约束与类型
Awaitable
 | 
 | 
Promise
 | 
 | 
Coroutine Handle
 | 
 | 
三大协程操作
co_return
相当于协程的 return。
协程完成所有 execution,除了 promise.final_suspend() 不再 suspend。
co_await
flowchart TD
COAWAIT[co_await awaitable;] --->|optional| TRANSFORM["promise.await_transform(awaitable)"]
TRANSFORM ---> COAWAIT
COAWAIT ---> AWAIT_READY{"awaitable.await_ready() -> bool"}
AWAIT_READY --->|true| CONTINUE["直接继续current_coroutine,避免不必要的 suspend"]
AWAIT_READY --->|false| SUSPEND["current_coroutine_handle.suspend()"]
SUSPEND ---> AWAIT_SUSPEND{"awaitable.await_suspend(current_coroutine_handle)"}
AWAIT_SUSPEND ---> AWAIT_SUSPEND_VOID(void)
AWAIT_SUSPEND_VOID ---> TRANSFER_CONTROL["返回控制权给 current_coroutine_handle の caller/resumer"]
AWAIT_SUSPEND ---> AWAIT_SUSPEND_BOOL(bool)
AWAIT_SUSPEND_BOOL --->|true| TRANSFER_CONTROL
AWAIT_SUSPEND_BOOL --->|false| RESUME_CURRENT["current_coroutine_handle.resume()"]
AWAIT_SUSPEND ---> AWAIT_SUSPEND_CORO(another_coroutine_handle)
AWAIT_SUSPEND_CORO ---> RESUME_ANOTHER["another_coroutine_handle.resume()"]
AWAIT_SUSPEND -...- AWAIT_SUSPEND_RESP["awaitable.await_suspend(cur_coro) 应处理好当前 coroutine 的 schedule 问题,如把 current coroutine handle 提交到一个 executor"]
co_yield
 | 
 | 
等价于
 | 
 | 
动态分配
C++ coroutine 作为无栈协程,默认使用 heap allocation (operator new/delete)
相比 static alloc 会少内联优化机会,且无法在嵌入式环境工作
可以自定义 allocator 并重载 operator new 调用解决