在C++里,一个函数如果其函数体实现中包含co_await、co_yield、co_return中任何一个关键字,那么这个函数就是一个coroutine。其中:

  1. co_await:挂起当前的coroutine
  2. co_return:从当前coroutine返回一个结果
  3. co_yield:返回一个结果并且挂起当前的coroutine

一个coroutine要能被编译期识别并通过编译,在某些情况下要自己去特化coroutine_traits。下面就一个简单的coroutine来说一说C++编译器是如何修改这个coroutine的。

 // 我们假定这个模板函数是一个coroutine
template <typename TRet, typename … TArgs>
TRet func(TArgs args…)
{
body; // body里至少包含了co_await、co_yield、co_return三者之一。
}

那么这个函数会被编译器改成如下形式:

 // 它会被编译期展开成如下形式
template <typename TRet, typename ... TArgs>
TRet func(TArgs args...)
{
using promise_t = typename coroutine_traits<TRet, TArgs...>::promise_type; promise_t promise;
auto __return__ = promise.get_return_object(); // 这个__return__会被编译器特殊处理 co_await promise.initial_suspend(); try
{ // co_return expr; => promise.return_value(expr); goto final_suspend;
body; // co_return;      => promise.return_void(); goto final_suspend;
} // co_yield expr;  => co_await promise.yield_value(expr);
catch (...)
{
promise.set_exception(std::current_exception());
} final_suspend:
co_await promise.final_suspend();
}

以上是一个coroutine的基本形式。事实上看完之后会发现,一个coroutine的关键主要还是和其关联的promise。
和coroutine promise关联的另外一个概念,叫awaitable。Awaitable可以称为一个可等待对象。一个awaitable对象需要实现3个相关函数:

  1. await_ready:awaitable实例是否已经ready
  2. await_suspend:挂起awaitable。该函数会传入一个coroutine_handle类型的参数。这是一个由编译器生成的变量。suspend过程可以指定该coroutine何时何地以何种方式被resume。比方说实现suspend函数时,将coroutine_handle放到threadpool中。那么当前的coroutine接下来就运行在线程池指派的后台线程中运行了。
  3. await_resume:当coroutine重新运行时,会调用该函数。

所以要让一个类型能够awaitable,有三种手段:

  1. 该类型相关代码无法修改时,需要实现:

    • bool await_ready(T &);
    • void await_suspend(T &, coroutine_handle<promise_type>);
    • auto await_resume(T &);  auto视具体情况而定
  2. 该类型相关代码可以修改时,需要增加3个成员函数:
    • bool await_ready();
    • void await_suspend(coroutine_handle<promise_type> ch);
    • auto await_resume();
  3. 实现operator co_await操作符,返回一个可等待的代理类型,并且实现了上述三个函数。

--完

N4663

C++ Coroutine简明教程的更多相关文章

  1. Gevent简明教程

    Gevent简明教程  发表于 2015-11-28 |  分类于 技术| |  阅读次数 5159 前述 进程 线程 协程 异步 并发编程(不是并行)目前有四种方式:多进程.多线程.协程和异步. 多 ...

  2. 2013 duilib入门简明教程 -- 第一个程序 Hello World(3)

    小伙伴们有点迫不及待了么,来看一看Hello World吧: 新建一个空的win32项目,新建一个main.cpp文件,将以下代码复制进去: #include <windows.h> #i ...

  3. 2013 duilib入门简明教程 -- 部分bug (11)

     一.WindowImplBase的bug     在第8个教程[2013 duilib入门简明教程 -- 完整的自绘标题栏(8)]中,可以发现窗口最大化之后有两个问题,     1.最大化按钮的样式 ...

  4. 2013 duilib入门简明教程 -- 部分bug 2 (14)

        上一个教程中提到了ActiveX的Bug,即如果主窗口直接用变量生成,则关闭窗口时会产生崩溃            如果用new的方式生成,则不会崩溃,所以给出一个临时的快速解决方案,即主窗口 ...

  5. 2013 duilib入门简明教程 -- 自绘控件 (15)

        在[2013 duilib入门简明教程 -- 复杂控件介绍 (13)]中虽然介绍了界面设计器上的所有控件,但是还有一些控件并没有被放到界面设计器上,还有一些常用控件duilib并没有提供(比如 ...

  6. 2013 duilib入门简明教程 -- 事件处理和消息响应 (17)

        界面的显示方面就都讲完啦,下面来介绍下控件的响应.     前面的教程只讲了按钮和Tab的响应,即在Notify函数里处理.其实duilib还提供了另外一种响应的方法,即消息映射DUI_BEG ...

  7. 2013 duilib入门简明教程 -- FAQ (19)

        虽然前面的教程几乎把所有的知识点都罗列了,但是有很多问题经常在群里出现,所以这里再次整理一下.     需要注意的是,在下面的问题中,除了加上XML属性外,主窗口必须继承自WindowImpl ...

  8. Mac安装Windows 10的简明教程

    每次在Mac上安装Windows都是一件非常痛苦的事情,曾经为了装Win8把整台Mac的硬盘数据都弄丢了,最后通过龟速系统恢复模式恢复了MacOSX(50M电信光纤下载了3天才把系统下载完),相信和我 ...

  9. Docker简明教程

    Docker简明教程 [编者的话]使用Docker来写代码更高效并能有效提升自己的技能.Docker能打包你的开发环境,消除包的依赖冲突,并通过集装箱式的应用来减少开发时间和学习时间. Docker作 ...

随机推荐

  1. jmeter接口自动化测试

    一.正常单个接口 1.自定义变量设置服务器地址ip和端口 2.可以正则表达式提取取出token值设置为请求头里 如图 二.接口请求参数涉及取参(单个或多值) 提取多个值参数,用Json提取器可以直接提 ...

  2. 201806 数据处理 SQL、python、shell 哪家强...速度PK(上篇)

    最近在工作中,进行大量的数据处理,使用的是mysql5.7.22,发现当数据量级达到几十万之后,SQL执行速度明显变慢.尤其是当多个表join时,于是就尝试用python pandas进行数据处理,发 ...

  3. Autofac IOC框架

    ASP.NET Core自带了一个轻量级的IOC容器     但是只提供了最基本的AddXXX方法来绑定实例关系     需要一个一个添加   可以使用其他IOC容器来替换内置的 ABP自带Castl ...

  4. 关于虹软人脸识别SDK的接入

    背景: 虹软的人脸识别还是不错的,在官方注册一个账号,成为开发者,下载SDK的jar包,在开发者中心,找一个demo就可以开始做了,安装里边的逻辑,先看理解代码,然后就可以控制代码,完成自己想要的功能 ...

  5. 杂记-python

    1.在cmd输入python -V显示当前python的版本信息,一定是大写的V 2.输入python,进入python解释器里面 3.在解释器中,输入exit()或者quit()会退出,一定要加括号 ...

  6. SQL添加事务处理

    --modi by lmt declare @errorSum int --记录错误数 begin Create table #CheckreqAccState(CheckReqID varchar( ...

  7. vue单位文本控件与vue加密文本控件

    vue单位文本控件: 使用方式: npm install dami-text-input --save 使用: <text-input v-model="test" :uni ...

  8. 移动端跨平台方案对比:React Native、weex、Flutter

    跨平台一直是老生常谈的话题,cordova.ionic.react-native.weex.kotlin-native.flutter等跨平台框架百花齐放,颇有一股推倒原生开发者的势头. 为什么我们需 ...

  9. 九度1456胜利大逃亡【BFS】

    时间限制:1 秒 内存限制:128 兆 特殊判题:否 提交:4432 解决:1616 题目描述: Ignatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会.魔王住在一个城堡 ...

  10. MongDB 批量更新

    最近公司在使用mongodb.  批量更新的语句为: db.table.update(  {'wo': {$in: [ "123", "456"]}}, {$s ...