前言
在理解传统异步编程后,我们开始探索 C++20 协程。协程是为了解决多个不同'异步耗时任务'的按流程序执行时产生的'回调地狱问题'。
C++20 协程的介绍
C++20 的协程是广义上的'函数',我们都知道普通的 C++ 函数只能够'被线程调用'、'一字不落全部执行才返回'。而协程是可以主动让出协程的控制权,不必等协程的内容全部执行完再返回。
关于协程的八股文:协程是用户态轻量级线程,由程序自身控制调度(非抢占式),在单线程内实现多任务协作式并发。
有两个特别的关键字 co_await 和 co_yield,这意味着任何一个 C++20 的协程,其协程的控制权有两个让出对象,第一个是让出给调用它的主协程,即 co_yield,另一个让出对象是其他线程 co_await。这种设计其实很巧妙,我们的协程可以通过线程间通信来实现异步任务处理,同时也可以主动让出给主协程,供其调度差遣,有相当大的灵活性。
协程真的很像一个函数,他不过是多了 恢复、异步执行、让出协程、协程返回 四个动作而已。线程里的主协程就是一整个程序的主线,而子协程是支线任务,就算分叉再多,弯弯绕绕再多,所有的协程执行完之后都得回到主协程里面。
书写一个协程
C++20 认为协程得要自己给自己定立规矩,协程要主动的区域其他协程进行协调协作,不可以做抢占线程的事情。所谓的规矩就是,异步等待、让出协程、协程返回、协程恢复的时候要做什么动作。只有订立了规矩,才有协作的基础,正如有了协议才有了网络通信,不然怎么叫'协程'呢?
而在 C++ 20 的协程库里面,有一种数据结构叫做 promise_type,他就是我们所要订立的'规矩',不仅要有规矩,还得要有异步调用链。定义一个写成所需要的大部分接口,都在下图显示。我们需要定义接口,来让这些关键字的使用有具体的语义。
还需要说明自己的协程运行到什么地方会让出协程、主协程什么时候会恢复协程、协程什么时候返回、主协程什么时候执行异步任务。这就是具体协程的实现了,这些实现都依赖于对协程接口的定义,完成了协程的接口定义,才可以书写协程,因为协程的挂起、让出、返回、恢复,这四个关键动作都是依赖于它们。
promise_type 是协程的规矩承诺
自定义一个类型,只要其'内嵌 / 组合'一个 promise_type 类型接口,再组合一个 coroutine_handle 的句柄,用来获取 promise_type 内部的数据(我们恢复协程、迭代器输出都是要使用这个句柄的),那么我们就可以定义出协程的一个蓝本。
#include <iostream>
std;
< T>
{
:
{
() { cout << << endl; }
~() { cout << << endl; }
{
cout << << endl;
Task{coroutine_handle<promise_type>::(*)};
}
{
cout << << endl;
{};
}
{
cout << << endl;
{};
}
{
cout << << endl;
}
{
cout << << endl;
}
{
cout << << value << endl;
value_ = (value);
{};
}
T value_;
};
{
handle_;
}
{
(!handle_ || handle_.()) std::;
handle_.();
(handle_.()) std::;
handle_.().value_;
}
(coroutine_handle<promise_type> handle) : (handle) {
cout << << endl;
}
~() {
cout << << endl;
(handle_) handle_.();
}
:
coroutine_handle<promise_type> handle_;
};


