C++ Coroutine简明教程

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

  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 }

那么这个函数会被编译器改为以下形式:spa

 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操做符,返回一个可等待的代理类型,而且实现了上述三个函数。

--完code

N4663对象

相关文章
相关标签/搜索