提问人:Nikitf777 提问时间:11/10/2023 最后编辑:Nikitf777 更新时间:11/10/2023 访问量:45
如何以最简单的方式C++使用co_await运算符?
How to use co_await operator in C++ the simpliest way?
问:
我应该做的最低限度的操作集是什么来使用 C++ 运算符(如 C# 运算符)?co_await
await
有一篇关于 cvotestense 的文章,其中有类似 C# 的类用作返回类型,但我在标准库中找不到它。当函数返回 void 时,这可预见地会导致编译错误。task<>
答:
task
在这种情况下,只是您自己组装的管道的占位符。
从 https://en.cppreference.com/w/cpp/language/coroutines
每个协程都必须具有满足许多要求的返回类型
当你在代码中使用时,你需要.编译器将对函数执行操作。例:co_*
#include <coroutine>
void csp_await() {
bidirectional_channel<int> ch;
co_await ch.send(1);
}
上面的代码会导致以下错误:
类“std::coroutine_traits”没有成员“promise_type”
无论编译器在做什么,它都在寻找一个,但它找不到它。promise_type
为了解决这个问题,我们需要引入以下代码。
struct task_handle {};
struct task : std::coroutine_handle<task_handle> {
using promise_type = task_handle;
};
函数的返回类型更改为使用我们的类型,这会导致不同的错误:csp_await
task
“task::p romise_type”没有成员“initial_suspend”
因此,我们添加了更多内容
struct task_handle;
struct task : std::coroutine_handle<task_handle> {
using promise_type = task_handle;
};
struct task_handle {
task get_return_object() { return {task::from_promise(*this)}; }
std::suspend_always initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
接下来要做的是使协程的功能友好。它目前是一个具有返回类型的阻塞函数,不能按原样使用。send
bidirectional_channel
void
template <typename T> struct send_async_awaiter {
bidirectional_channel<int> &ch_;
T val_;
bool await_ready() const noexcept { return false; }
void await_suspend(std::coroutine_handle<> handle) {}
void await_resume() noexcept {}
};
template <typename T> send_async_awaiter<T> send_async(bidirectional_channel<T> &ch, const T &val) {
return send_async_awaiter{ch, val};
}
send_async_awaiter
是我们可等待的、协程友好的类型。 正是函数需要更改为可等待的内容。此代码可编译,但不执行任何操作。send_async
send
我不想对 CSP 进行此介绍,但我需要详细介绍通道发送函数中需要发生的情况。在此示例中,我使用了一个无缓冲通道,该通道应暂停,直到有现成的接收器。假设接收方还没有准备好开始,我们需要将发送操作停放在某个地方。为此,我们只需要考虑 和 . 返回 false,因此接下来要发生的事情将是 。我们得到了一个协程的通用句柄,我们可以用它来停放它。await_ready
await_suspend
await_ready
await_suspend
我开始的实现是基于线程的。它使用互斥锁和条件变量来唤醒阻塞的线程,但我认为类型不应该以相同的方式实现。相反,我将考虑一种侵入性方法,将悬挂的协程停放在通道内。我认为这是有道理的,因为这是我以后需要能够找到一个停放的协程,以便在接收器准备就绪时恢复。这也意味着我们可以编写一个完全单线程的 CSP 库,该库使用协作式而不是抢占式多线程。我认为向这个异步CSP库添加并行性比采用另一种方式更容易。bidirectional_channel
bidirectional_channel_async
我没有在这里详细介绍所有内容,但这是一个开始。我很高兴它像这样解耦,因为你可以在此基础上构建任何你认为最好的东西。
评论
task
co_await
co_await