在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. 修改vim的颜色主题 及显示行号

    1.打开vim窗口,输入命令:color 或者colorscheme后回车查看当前颜色主题. 2. 输入:colorscheme <主题> 即可设置当前vim的颜色主题. sample: ...

  2. Redis5.0+哨兵模式+Keepalived实现高可用

    Redis主备配置 原理: 从服务器向主服务器发出SYNC指令,当主服务器接到此命令后,就会调用BGSAVE指令来创建一个子进程专门进行数据持久化工作,也就是将主服务器的数据写入RDB文件中.在数据持 ...

  3. 小程序之 微信小程序下拉上方出现空白

    往下拉页面后上方出现空白区域  用户需要手动划上去才能消失 方法一:"enablePullDownRefresh":false //这个在page.json中配置 整个页面都不能滑 ...

  4. 浮点型/小数/栅格图层转为整数型arcgis操作

    有时候会遇到将32位栅格数据提取属性表的操作,但是一般此类数据都是浮点型,是无法计算得到属性表的.因此我们可以利用数据管理工具下的: 复制栅格工具,在最下面选择16位即可,看自己数据情况选择signe ...

  5. java.nio.file.NoSuchFileException

    springboot +es es 2.1.0 参考这个 https://www.cnblogs.com/yueshutong/p/9381543.html cluster-nodes :改成127. ...

  6. Active Record Query Interface 数据查询接口(界面) 看到第8节。

    http://guides.rubyonrails.org/active_record_querying.html ✅How to find records using a variety of me ...

  7. D - Dice Game (BFS)

    A dice is a small cube, with each side having a different number of spots on it, ranging from 1 to 6 ...

  8. 『高性能模型』轻量级网络ShuffleNet_v1及v2

    项目实现:GitHub 参考博客:CNN模型之ShuffleNet v1论文:ShuffleNet: An Extremely Efficient Convolutional Neural Netwo ...

  9. python 字典 dict 该注意的一些操作

    在用python处理dict 的时候,有几个该注意的地方,这里跟大家提一下: 1)操作dict 时,尽量少产生新的列表对象.比如: 遍历dict的时候,如果用 dic = {"a" ...

  10. VUE初体验篇-安装

    现代前端框架大行其道,讲前端思想从操作dom的阶段,升级到操作数据的阶段.vue作为三大前端框架之一,其中平缓的学习曲线,让好多前端新手非常喜欢,应用也越来越广泛.虽然其他两个框架有facebook, ...