co_await expr
co_await(协待)
是C++20
新关键字.上面表示等待懒求值
任务.不希望该任务阻塞调用者
,用协待
挂起任务
.调用者继续.任务完成后,协待
返回协程
的结果.有两个作用:挂起协程及取协程返回值
.
协待
等待任务时,不阻塞调用者
,就是协程
化异步
为同步
的关键.
协待
类似调用函数
.对象有()
时是可调用
的.对象支持协待()
时,就是可等待
的.协待
后的式
为可等待
式.
总是挂起
协待 从不挂起;
空 测试(){协待 总是挂起{};
}
协待
必须在协程
中,协程
必须要有承诺类型
.通过它返回内外通信对象
.
构 任务{构 承诺类型{任务 取中对象(){中{协程句柄<任务::承诺类型>::从承诺(*本)};}从不挂起 初始挂起(){中{};}从不挂起 止挂起()无异{中{};}空 中空(){}空 未处理异常(){}};协程句柄<任务::承诺类型>句柄_;
};任务 测试(){协待 总是挂起{};
}
.1
转换为前面见过的模板框架代码
:
{动&&值&#61;总是挂起{};
动&&w&#61;取可等待(承诺,静转<推导(值)>(值));
动&&等待器&#61;取等待器(静转<推导(w)>(w));如(!等待器.准备好协()){用 句柄型&#61;实验::协程句柄<P>;用 等待挂起果型&#61;推导(等待器.挂起协(句柄型::从承诺(p)));<挂起协程>如 常式(是空值<等待挂起果型>){等待器.挂起协(句柄型::从承诺(p));<返回到调用者或恢复者>} 异 {静断(是相同值<等待挂起果型,极>,"挂起协()必须中&#39;空&#39;或&#39;极&#39;.");如(等待器.挂起协(句柄型::从承诺(p))){<返回到调用者或恢复者>}}<恢复点>}中 等待器.恢复协();
}
元<类 P,类 T>
推导(动)取可等待(P&承诺,T&&式)
{如 常式(有任何等待转换成员值<P>)中 承诺.等待转换(静转<T&&>(式));异中 静转<T&&>(式);
}
如果协程的承诺
中定义了await_transform
,那么就调用它
来得到可等待
,否则就按可等待
返回自己,这里,未在task
里面定义await_transform
,因此总是挂起
将为可等待
,实现代码:
构 总是挂起{常式 极 准备好协()常 无异 中 假;常式 空 挂起协(协程句柄<>)常 无异{}常式 空 恢复协()常 无异{}
};
取了总是挂起
后,再根据它来取等待器
,代码:
元<类 W>
推导(动)取等待器(W&&w)
{如 常式(有成员操作符协待值<W>)中 静转<W&&>(w).符号 协待();异 如 常式(无成员操作符协待值<W&&>)中 符号 协待(静转<W&&>(w));异中 静转<W&&>(w);
}
等待器
是可等待
的返回对象
.1,用专门带约束
对象来实现挂起协程
和取协程返回值
.2,灵活性和扩展性
.可等待
作为间接层,保存协待
环境,可做更多事情.
等待器
必须实现准备好等待(.1)/挂起等待(.2)/恢复等待(.3)
.
.1
为假,就挂起协程,调用.2
.如果.2
返回真/空
,就返回到调用者
.返回假
,就执行协待
下面语句..1
为真,说明执行完协程,调用.3
返回协程结果
.
展示协待
构 任务{构 承诺类型{任务 取中对象(){中{协程句柄<任务::承诺类型>::从承诺(*本)};}从不挂起 初始挂起(){中{};}从不挂起 止挂起()无异{中{};}空 中空(){ 输出<<"取协程结果\n"; }空 未处理异常(){}};协程句柄<任务::承诺类型>句柄_;
};任务 测试(){输出<<"创建协程\n";协待 总是挂起{};输出<<"这是恢复点\n";
}
整 主(){动 t&#61;测试();输出<<"现在返回调用者\n";输出<<"调用者恢复挂起协程\n";t.句柄_();输出<<"消灭协程\n";
}
可定义等待器
,控制它的.1和.2
来控制协程.
一般在.2
中发起异步
操作,此时协程
是挂起的.返回调用者
不阻塞.完成异步
操作后,通过.3
返回协程返回值
,并恢复协程.结束协待
,调用者拿到结果
.