如何使用C++20的协程实现异步任务?

C++20 的协程(co_awaitco_yieldco_return)为异步编程提供了更直观的语法。下面通过一个简单的示例,演示如何利用协程来实现一个异步任务调度器。

1. 协程类型概览

  • promise_type:协程的承诺对象,负责管理协程的生命周期。
  • handle_type:协程句柄,用于控制协程(挂起、恢复、销毁)。
  • awaiterco_await 的等待对象,定义 await_readyawait_suspendawait_resume 三个方法。

2. 简单的异步函数

#include <coroutine>
#include <iostream>
#include <thread>
#include <chrono>
#include <optional>

struct AsyncResult {
    struct promise_type {
        std::optional <int> value_;
        std::coroutine_handle <promise_type> caller_;

        AsyncResult get_return_object() {
            return AsyncResult{ std::coroutine_handle <promise_type>::from_promise(*this) };
        }
        std::suspend_always initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept {
            if (caller_) caller_.resume();
            return {};
        }
        void return_value(int v) { value_ = v; }
        void unhandled_exception() { std::terminate(); }
    };

    std::coroutine_handle <promise_type> coro_;
    AsyncResult(std::coroutine_handle <promise_type> h) : coro_(h) {}
    ~AsyncResult() { if (coro_) coro_.destroy(); }
};

struct AwaitableSleep {
    std::chrono::milliseconds dur_;
    AwaitableSleep(std::chrono::milliseconds d) : dur_(d) {}

    bool await_ready() const noexcept { return false; }

    void await_suspend(std::coroutine_handle<> h) {
        std::thread([h, dur = dur_]() {
            std::this_thread::sleep_for(dur);
            h.resume();
        }).detach();
    }

    void await_resume() const noexcept {}
};

AsyncResult async_task() {
    std::cout << "Task started\n";
    co_await AwaitableSleep{ std::chrono::seconds(2) };
    std::cout << "Task resumed after sleep\n";
    co_return 42;
}

int main() {
    auto task = async_task();
    // 模拟事件循环
    while (true) {
        if (!task.coro_.done()) {
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        } else {
            std::cout << "Result: " << task.coro_.promise().value_.value() << '\n';
            break;
        }
    }
    return 0;
}

3. 代码解析

  1. AsyncResult 包装协程句柄,提供了简洁的使用接口。
  2. AwaitableSleep 是一个可等待对象,内部使用一个独立线程来实现非阻塞睡眠,睡眠结束后恢复协程。
  3. async_task 展示了如何在协程内部 co_await 自定义等待对象,然后返回一个结果。
  4. main 充当事件循环,持续检查协程是否完成。

4. 进一步扩展

  • 任务调度:将 AwaitableSleep 换成网络 I/O 或数据库查询的 awaitable。
  • 错误处理:在 promise_type 中实现 unhandled_exception,将异常信息传递给外部。
  • 多任务:使用 `std::vector ` 进行并行任务管理。

通过上述示例,你可以快速掌握 C++20 协程的基本使用模式,为构建高性能异步框架奠定基础。

发表评论