Skip to content

C++20 Coroutines

C++20 协程是语言级别的异步编程支持,通过 co_await/co_yield/co_return 让异步代码像同步代码一样书写。

核心概念

协程三要素:
co_await  — 挂起当前协程,等待异步操作完成
co_yield  — 挂起并产出一个值(生成器)
co_return — 协程返回值并结束

协程机制:
Promise   — 控制协程的行为(如何挂起、如何返回值)
Awaitable — 可以被 co_await 的对象
Coroutine Handle — 协程的句柄,用于恢复执行

生成器(Generator)

cpp
#include <coroutine>
#include <optional>

// 简单生成器实现
template<typename T>
class Generator {
public:
    struct promise_type {
        T current_value;

        Generator get_return_object() {
            return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_always initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        std::suspend_always yield_value(T value) {
            current_value = std::move(value);
            return {};
        }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };

    using handle_type = std::coroutine_handle<promise_type>;

    explicit Generator(handle_type h) : handle_(h) {}
    ~Generator() { if (handle_) handle_.destroy(); }

    Generator(Generator&& other) noexcept : handle_(other.handle_) {
        other.handle_ = nullptr;
    }

    // 迭代器支持
    struct iterator {
        handle_type handle;
        bool operator!=(std::default_sentinel_t) const { return !handle.done(); }
        iterator& operator++() { handle.resume(); return *this; }
        T& operator*() { return handle.promise().current_value; }
    };

    iterator begin() { handle_.resume(); return {handle_}; }
    std::default_sentinel_t end() { return {}; }

private:
    handle_type handle_;
};

// 使用生成器
Generator<int> fibonacci() {
    int a = 0, b = 1;
    while (true) {
        co_yield a;
        auto next = a + b;
        a = b;
        b = next;
    }
}

Generator<int> range(int start, int end, int step = 1) {
    for (int i = start; i < end; i += step) {
        co_yield i;
    }
}

// 使用
for (int n : range(0, 10, 2)) {
    std::cout << n << " ";  // 0 2 4 6 8
}

auto fib = fibonacci();
int count = 0;
for (int n : fib) {
    if (count++ >= 10) break;
    std::cout << n << " ";  // 0 1 1 2 3 5 8 13 21 34
}

异步任务(Task)

cpp
#include <coroutine>

// 简单 Task 实现(类似 C# Task / Rust Future)
template<typename T = void>
class Task {
public:
    struct promise_type {
        std::optional<T> result;
        std::exception_ptr exception;
        std::coroutine_handle<> continuation;  // 等待此 Task 的协程

        Task get_return_object() {
            return Task{std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() { return {}; }

        struct FinalAwaiter {
            bool await_ready() noexcept { return false; }
            void await_resume() noexcept {}
            std::coroutine_handle<> await_suspend(
                std::coroutine_handle<promise_type> h) noexcept {
                if (h.promise().continuation)
                    return h.promise().continuation;
                return std::noop_coroutine();
            }
        };
        FinalAwaiter final_suspend() noexcept { return {}; }

        void return_value(T value) { result = std::move(value); }
        void unhandled_exception() { exception = std::current_exception(); }
    };

    using handle_type = std::coroutine_handle<promise_type>;

    // Awaitable 接口
    bool await_ready() { return handle_.done(); }
    void await_suspend(std::coroutine_handle<> h) {
        handle_.promise().continuation = h;
    }
    T await_resume() {
        if (handle_.promise().exception)
            std::rethrow_exception(handle_.promise().exception);
        return std::move(*handle_.promise().result);
    }

    explicit Task(handle_type h) : handle_(h) {}
    ~Task() { if (handle_) handle_.destroy(); }

private:
    handle_type handle_;
};

// 使用 Task
Task<int> fetch_data(int id) {
    // 模拟异步操作
    co_return id * 42;
}

Task<std::string> process() {
    int data = co_await fetch_data(10);  // 等待异步结果
    co_return "result: " + std::to_string(data);
}

实用库:cppcoro / libcoro

cpp
// 实际项目中使用成熟的协程库
// cppcoro:https://github.com/lewissbaker/cppcoro
// libcoro:https://github.com/jbaldwin/libcoro

#include <cppcoro/task.hpp>
#include <cppcoro/sync_wait.hpp>
#include <cppcoro/when_all.hpp>

cppcoro::task<int> compute(int x) {
    co_return x * x;
}

cppcoro::task<void> main_task() {
    // 顺序执行
    int r1 = co_await compute(3);
    int r2 = co_await compute(4);

    // 并发执行
    auto [a, b] = co_await cppcoro::when_all(compute(5), compute(6));

    std::cout << r1 << " " << r2 << " " << a << " " << b << "\n";
}

int main() {
    cppcoro::sync_wait(main_task());
}

Boost.Asio 协程

cpp
#include <boost/asio.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/use_awaitable.hpp>

namespace asio = boost::asio;
using tcp = asio::ip::tcp;

// 协程风格的异步 HTTP 请求
asio::awaitable<std::string> fetch(std::string host, std::string path) {
    auto executor = co_await asio::this_coro::executor;
    tcp::resolver resolver(executor);

    // 异步 DNS 解析(看起来像同步!)
    auto endpoints = co_await resolver.async_resolve(host, "80",
                                                      asio::use_awaitable);

    tcp::socket socket(executor);
    co_await asio::async_connect(socket, endpoints, asio::use_awaitable);

    std::string request = "GET " + path + " HTTP/1.0\r\nHost: " + host + "\r\n\r\n";
    co_await asio::async_write(socket, asio::buffer(request), asio::use_awaitable);

    std::string response;
    co_await asio::async_read_until(socket, asio::dynamic_buffer(response),
                                    "\r\n\r\n", asio::use_awaitable);
    co_return response;
}

int main() {
    asio::io_context io;
    asio::co_spawn(io, fetch("example.com", "/"), [](auto eptr, std::string result) {
        if (eptr) std::rethrow_exception(eptr);
        std::cout << result << "\n";
    });
    io.run();
}

关键认知

C++20 协程是无栈协程(stackless),挂起时只保存局部状态,内存开销极小。标准库只提供底层机制,实际使用需要配合 Boost.Asio、cppcoro 等库。协程让异步代码的可读性接近同步代码,是高性能 I/O 的未来方向。

系统学习 C++ 生态,深入底层架构