如何以最简方式使用C++的co_await运算符,实现类似C# await的效果?
实现C++协程类似C# await的最小代码量
要让C的co_await实现近似C# await的基础功能,你需要自定义一个最简化的task<T>类(以及配套的协程承诺类型)——因为C标准库并未内置这类协程返回类型,且协程函数不能直接返回void(会触发编译错误,因为void不满足协程返回类型的要求)。
以下是可运行的最小核心代码:
#include <coroutine> #include <iostream> #include <utility> template<typename T> struct task; // 协程承诺类型,负责管理协程状态与结果 template<typename T> struct task_promise { T result; std::coroutine_handle<> continuation; auto get_return_object() { return task<T>{std::coroutine_handle<task_promise>::from_promise(*this)}; } auto initial_suspend() { return std::suspend_always{}; } auto final_suspend() noexcept { struct awaitable { bool await_ready() noexcept { return false; } void await_suspend(std::coroutine_handle<task_promise> h) noexcept { h.promise().continuation.resume(); } void await_resume() noexcept {} }; return awaitable{}; } void return_value(T value) { result = std::move(value); } void unhandled_exception() { std::terminate(); } }; // 协程返回类型,支持co_await template<typename T> struct task { using promise_type = task_promise<T>; std::coroutine_handle<promise_type> handle; task(std::coroutine_handle<promise_type> h) : handle(h) {} ~task() { if (handle) handle.destroy(); } // 禁止拷贝,允许移动 task(const task&) = delete; task& operator=(const task&) = delete; task(task&& other) noexcept : handle(other.handle) { other.handle = nullptr; } task& operator=(task&& other) noexcept { if (this != &other) { if (handle) handle.destroy(); handle = other.handle; other.handle = nullptr; } return *this; } // 实现co_await的核心逻辑 bool await_ready() { return false; } void await_suspend(std::coroutine_handle<> h) { handle.promise().continuation = h; handle.resume(); } T await_resume() { return std::move(handle.promise().result); } }; // 针对void类型的特化 template<> struct task_promise<void> { std::coroutine_handle<> continuation; auto get_return_object() { return task<void>{std::coroutine_handle<task_promise>::from_promise(*this)}; } auto initial_suspend() { return std::suspend_always{}; } auto final_suspend() noexcept { struct awaitable { bool await_ready() noexcept { return false; } void await_suspend(std::coroutine_handle<task_promise> h) noexcept { h.promise().continuation.resume(); } void await_resume() noexcept {} }; return awaitable{}; } void return_void() {} void unhandled_exception() { std::terminate(); } }; template<> struct task<void> { using promise_type = task_promise<void>; std::coroutine_handle<promise_type> handle; task(std::coroutine_handle<promise_type> h) : handle(h) {} ~task() { if (handle) handle.destroy(); } task(const task&) = delete; task& operator=(const task&) = delete; task(task&& other) noexcept : handle(other.handle) { other.handle = nullptr; } task& operator=(task&& other) noexcept { if (this != &other) { if (handle) handle.destroy(); handle = other.handle; other.handle = nullptr; } return *this; } bool await_ready() { return false; } void await_suspend(std::coroutine_handle<> h) { handle.promise().continuation = h; handle.resume(); } void await_resume() {} }; // 示例协程函数 task<int> compute_value() { co_return 42; } task<void> print_value() { int val = co_await compute_value(); std::cout << "Computed value: " << val << std::endl; } int main() { auto t = print_value(); // 手动启动协程(因为initial_suspend是suspend_always) t.handle.resume(); return 0; }
关键部分说明
task_promise<T>:协程的核心管理类型,负责存储协程结果、处理挂起/恢复逻辑,定义协程的返回对象、初始/最终挂起行为。task<T>:作为协程的返回类型,实现了co_await所需的三个方法(await_ready、await_suspend、await_resume),让外部代码可以通过co_await等待协程完成并获取结果。void类型特化:针对不返回值的协程,提供对应的task<void>和task_promise<void>实现,避免返回void导致的编译错误。- 为什么不能返回
void:C++协程要求返回类型必须包含嵌套的promise_type类型定义,void不满足这一要求,因此必须使用自定义的task类(哪怕是无返回值的task<void>)。
这个最小实现已经能模拟C# await的基础行为:允许协程挂起等待另一个协程完成,获取其结果后继续执行。如果需要更复杂的异步调度(比如线程池支持),可以在此基础上扩展,但核心框架就是上述代码。
内容的提问来源于stack exchange,提问作者Nikitf777
相关产品推荐
相关产品推荐

