promise_type
中的三个函数返回可等待体 yield_value
, initial_suspend
, final_suspend
可等待体决定协程是否暂停
本质上,编译器使用promise和co_await操作符生成这三个函数调用。
co_await
需要一个可等待体作为参数
实现可等待体需要三个函数
C++20标准已经定义了两个基本的对象:std::suspend_always
,std::suspend_never
The Awaitable std::suspend_always
struct suspend_always {
constexpr bool await_ready() const noexcept { return false; }
constexpr void await_suspend(std::coroutine_handle<>) const noexcept {}
constexpr void await_resume() const noexcept {}
};
总是挂起,await_ready
返回false
The Awaitable std::suspend_never
struct suspend_never {
constexpr bool await_ready() const noexcept { return true; }
constexpr void await_suspend(std::coroutine_handle<>) const noexcept {}
constexpr void await_resume() const noexcept {}
};
从不挂起,await_ready
返回true
当协程协程执行的时候,这两个函数会自动执行:
initial_suspend
final_suspend
当initial_suspend返回suspend_always时,协程会在开始时挂起;返回suspend_never时,则不会挂起
A lazy coroutine
std::suspend_always initial_suspend() {
return {};
}
A eager coroutine
std::suspend_never initial_suspend() {
return {};
}
在协程结束时执行,与几乎initial_suspend相同
编译器执行两个工作流外部的promise
工作流和内部的awaiter
工作流
当在函数中使用co_yield, co_await, co_return
,函数成为一个协程,并且编译器将其转换成等价的如下代码
The transformed coroutine
主要工作步骤:
promise_type
对象promise_type
中的get_return_object
方法创建协程句柄(coroutine handle
),并保持在局部变量中,当协程第一次挂起时,将返回给调用者initial_suspend
并且co_await
其结果,可能返回suspend_always/never
co_await prom.initial_suspend
恢复resume
时,函数体执行co_return
prom.retrun_void/value
没有返回值或者返回值prom.final_suspend()
并且co_await
它的结果promise_type
对象和函数参数对象的析构函数co_await
执行等待器工作流调用co_await
会让编译器执行三个函数:await_ready await_suspend await_resume
The generated Awaiter Workflow
只有await_ready
返回false
时,流程才会执行,否则的话直接返回await_resume
的结果
await_ready
返回false
时:
awaitable.await_suspend()
的返回值,返回值有很多种情况出现异常情况不想写了
协程使用co_return
作为返回语句
template <typename T>
struct MyFuture
{
std::shared_ptr<T> value;
MyFuture(std::shared_ptr<T> p): value(p)
{
}
~MyFuture()
{
}
T get()
{
return *value;
}
struct promise_type
{
std::shared_ptr<T> ptr = std::make_shared<T>();
~promise_type()
{
}
MyFuture<T> get_return_object() { return ptr; }
void return_value(T v) { *ptr = v; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void unhandled_exception()
{
std::terminate();
}
};
};
MyFuture<int> createFuture()
{
co_return 2021;
}
int main(int argc, char* argv[])
{
auto fut = createFuture();
std::cout << fut.get() << std::endl;
}
promise_type
对象promise_type
中的get_return_object
方法将ptr
传给fut
co_return
return_value
并传入参数2022fut.get()
无限数据流
template <typename T>
struct Generator
{
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
Generator(handle_type h): coro(h)
{
}
handle_type coro;
~Generator() { if (coro) coro.destroy(); }
Generator(const Generator&) = delete;
Generator& operator =(const Generator&) = delete;
Generator(Generator&& oth) noexcept : coro(oth.coro)
{
oth.coro = nullptr;
}
Generator& operator =(Generator&& oth) noexcept
{
coro = oth.coro;
oth.coro = nullptr;
return *this;
}
T getValue()
{
return coro.promise().current_value;
}
bool next()
{
coro.resume();
return !coro.done();
}
struct promise_type
{
promise_type() = default;
~promise_type() = default;
auto initial_suspend()
{
return std::suspend_always{};
}
auto final_suspend() noexcept
{
return std::suspend_always{};
}
auto get_return_object()
{
return Generator{handle_type::from_promise(*this)};
}
auto return_void()
{
return std::suspend_never{};
}
auto yield_value(const T value)
{
current_value = value;
return std::suspend_always{};
}
void unhandled_exception()
{
std::terminate();
}
T current_value;
};
};
Generator<int> getNext(int start = 0, int step = 1)
{
auto value = start;
while (true)
{
co_yield value;
value += step;
}
}
int main(int argc, char* argv[])
{
auto gen = getNext();
for (int i = 0; i <= 10; ++i)
{
gen.next();
std::cout << std::format("gen value: {}\n", gen.getValue());
}
std::cout << "\n\n";
auto gen2 = getNext(100, -10);
for (int i = 0; i <= 20; ++i)
{
gen2.next();
std::cout << std::format("gen2 value: {}\n", gen2.getValue());
}
}
看一下执行流程;
promise_type
get_return_object()
,将其结果保存在局部变量generator
initial_suspend
挂起协程gen.next
重复循环因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- oldu.cn 版权所有 浙ICP备2024123271号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务