协程化​​异步网络库​​是大势所趋.

​c++20协程​​是​​无栈​​协程,提供了:

​1​​,三个​​(协待(co_await),co_yield​​和​​co_return)​​新关键字

​2​​,几个新类型:​​coroutine_handle,coroutine_traits<T...>,suspend_always,suspend_never​

​3​​,和​​协程​​通信机制(通过​​协程函数​​的​​返回对象​​通信)

编译器根据​​c++​​协程关键字(​​协待,co_yield​​和​​co_return​​)生成​​协程​​模板框架.

需要定制框架中的​​各个可定制点​​,来实现协程的​​绝大部分行为​​.

由​​initial_suspend​​和​​final_suspend​​的返回类型来决定是否​​挂起​​协程.

在​​unhandled_exception​​里处理异常,在​​return_value​​里保存​​协程​​返回值.

存在​​协待,co_yield​​和​​co_return​​三个关键字之一,就是​​协程​​.

Task<int> sum(int a, int b) {
co_return 42;
}

生成:

{
协待 承诺.初始挂起();//挂起

{
承诺.返回值(42); 止挂起;
}//保存协程返回值
(...)
{
承诺.未处理异常();//处理异常
}
止挂起:
协待 承诺.止挂起();//止挂起.
}

由​​initial_suspend​​和​​final_suspend​​的​​返回类型​​来决定是否挂起.定制这些​​函数​​来灵活控制​​协程​​.

协待生成:

{
&&=<>;
&&可等待=取可等待(承诺,静转<推导()>());
&&等待器=取等待器(静转<推导(可等待)>(可等待));
//保存状态,准备恢复.
(!等待器.准备好协())//未准备好
{
句柄型=实验::协程句柄<P>;
等待挂起果型=推导(等待器.挂起协(句柄型::从承诺(p)));//挂起协,

<挂起协程>

常式(是空值<等待挂起果型>)
{//挂起协//第1个断点
等待器.挂起协(句柄型::从承诺(p));
<返回到调用者或恢复者>
}//在挂起协时,暂停协程的第1个断点.

{
静断(是相同值<等待挂起果型,>,
"挂起协()必须中'空'或'极'.");

(等待器.挂起协(句柄型::从承诺(p)))
{//挂起协
<返回到调用者或恢复者>
}
}
//协程暂停后,就可`恢复或销毁`
//断点处`转移回调用者或恢复者`,从`本地堆栈帧`弹出,但保持`协程帧`活跃.

<恢复点>
}//断点处恢复协程,

等待器.恢复协();//恢复了,取操作结果.
}

< P, T>
推导()取可等待(P&承诺,T&&)
{
常式(有任何等待转换成员值<P>)
承诺.等待转换(静转<T&&>());

静转<T&&>();
}

< W>
推导()取等待器(W&&w)
{//W为可等待
常式(有成员操作符协待值<W>)
静转<W&&>(w).符号 协待();
常式(无成员操作符协待值<W&&>)
符号 协待(静转<W&&>(w));

静转<W&&>(W);
}

在​​协待​​的​​模板​​框架里,可定制​​await_ready,挂起协​​和​​恢复协​​等.

从​​挂起协()​​的调用返回时,​​挂起协()​​的返回值为​​void​​的版本,无条件地将执行​​转移回​​协程的​​调用者/恢复者​​,而返回值为​​bool​​的版本允许​​awaiter​​对象​​有条件​​地返回并​​立即恢复协程​​,而不是返回​​调用者/恢复者​​.

​挂起协()​​的​​bool​​返回版本在​​awaiter​​可能​​启动异步​​操作(也可同步)时​​非常有用​​.在同步时,​​挂起协()​​方法,可返回​​假​​来指示应立即​​恢复协程​​并继续执行.

在开头,保存​​协程​​的​​当前状态​​并准备恢复.

完成操作后,​​挂起协()​​负责​​未来​​调度并恢复(或消灭)协程.注意,从​​挂起协()​​中返回​​假​​算​​调度协程​​,以便在​​当前线程​​上立即恢复.

​await_ready​​,已完成操作时,不必花费成本.

​恢复协()​​方法调用的​​返回值​​,成为​​协待​​表达式的结果.​​恢复协()​​方法也可​​抛异常​​,此时,异常从​​协待​​表达式中抛出.

注意,如果从​​挂起协()​​抛异常,则​​协程​​会自动恢复,并且异常会从​​协待​​表达式抛出而不调用​​恢复协()​​.