zoukankan      html  css  js  c++  java
  • C++ Coroutine简明教程

    在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的。

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

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

     1 // 它会被编译期展开成如下形式
     2 template <typename TRet, typename ... TArgs>
     3 TRet func(TArgs args...)
     4 {
     5     using promise_t = typename coroutine_traits<TRet, TArgs...>::promise_type;
     6 
     7     promise_t promise;
     8     auto __return__ = promise.get_return_object();    // 这个__return__会被编译器特殊处理
     9 
    10     co_await promise.initial_suspend();
    11 
    12     try
    13     {            // co_return expr; => promise.return_value(expr); goto final_suspend;
    14         body;    // co_return;      => promise.return_void(); goto final_suspend;
    15     }            // co_yield expr;  => co_await promise.yield_value(expr);
    16     catch (...)
    17     {
    18         promise.set_exception(std::current_exception());
    19     }
    20 
    21 final_suspend:
    22     co_await promise.final_suspend();
    23 }

    以上是一个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

  • 相关阅读:
    内部类与外部类的调用
    Docker学习(十二)中遇到的一些问题汇总
    Docker学习(十一)Docker系列结束-新的开始K8S
    Docker学习(十)Docker容器编排 Docker-compose
    Docker学习(九)Volumn容器间共享数据
    Docker学习(八)容器间单向通信
    Docker学习(七)实战
    Docker学习(六)Dockerfile构建自定义镜像
    Docker学习(五) Dockerfile基础命令
    Docker学习(四)Docker搭建Tomcat
  • 原文地址:https://www.cnblogs.com/wpcockroach/p/7403460.html
Copyright © 2011-2022 走看看