上一个文章我们说过各个关键类之间的关系,现在我们来详细说一下各个关键类所需要的接口,下面就按照协程创建关键类的顺序依次解释。
我们知道co_await调用首先会由编译器生成Promise关键类,关于Promise对象生成主要有两种方式
1、co_await expr中expr返回值存在promise_type
2、扩展std::coroutine_traits
关于Promise类的生成这里就不展开说,下面我们来聊一聊Promise关键类接口:
接口 | 说明 | 是否必须 |
void* operator new() | 自定义分配协程帧需要的大小,用于存放Promise、函数参数、局部变量等 | 否 |
P::get_return_object_on_allocation_failure() | 如果operator new调用返回 nullptr ,那么协程将立即调用 P::get_return_object_on_allocation_failure() 并将结果返回给协程的调用者,而不是抛出异常。 | 否 |
Awaitable await_transform() | 获取awaitable / awaiter | 否 |
get_return_object() | 在 promise 对象上定义的特殊方法,用于获取一个表示协程返回值的临时对象。这个临时对象允许在协程的主体中执行挂起操作后将结果传递给调用者。 | 是 |
auto initial_suspend() noexcept | 在 promise 对象上定义的特殊方法,其目的是控制协程在开始时是否立即挂起,或者应该立即开始执行 | 是 |
return_void() return_value(<expr>) | 如果协程返回类型为 如果协程返回类型为其他类型,将使用 | 是 |
void unhandled_exception() noexcept | 将异常捕获并保存以便在稍后的上下文中重新抛出。 | 否 |
auto final_suspend() noexcept | 允许协程在执行到完成的时候选择是否立即暂停,等待某个时机再继续执行。通常,在这个点上,协程可以执行一些逻辑,比如发布结果、发出完成信号或恢复继续执行 | 是 |
void operator delete() | 释放用于协程帧的内存(协程的内存管理方式可能因编译器而异,一些编译器可能会采用不同的优化策略,甚至可能完全忽略 operator delete 的调用,而直接回收协程帧的内存) | 否 |
读过开头链接文章的朋友肯定知道,Promise创建后通过两个步骤获取到Awaiter关键类,但是在此之前会创建一个Awaitable关键类,所以,接下来我们将描述Awaitable关键类接口,如下:
接口 | 说明 | 是否必须 |
awaiter operator co_await() const noexcept | 创建Awaiter | 否 |
awaiter operator co_await(Awaitable&& ) const noexcept | 创建Awaiter | 否 |
我们知道co_await运算符重载并不是必须的,如果没有实现此接口,则编译器会直接使用 expr对象作为 Awaiter
对象,所以Awaitable也可能需要以下接口,(Awaiter同如):
接口 | 说明 | 是否必须 |
bool await_ready() const noexcept | 决定是否挂起协程 返回false挂起 | 是 |
bool await_suspend(std::experimental::coroutine_handle<> awaitingCoroutine) noexcept | 当前协程挂起 | 是 |
void await_resume() noexcept | 协程恢复 | 是 |
以上就是各个关键类接口介绍,里面介绍了当异常发生后如何不抛出异常的接口以及当某个接口不实现时各个类型之间的转换关系等。通过这些,相信大家肯定能自定义出自己的协程。关于协程关键类接口就介绍到这里。