一、协程的核心概念

C++20引入了编译器级别的协程支持,但保留了极高的灵活性。理解协程帧(Coroutine Frame)和Promise对象,是掌握C++协程的关键。

1.1 协程的三要素

// C++协程必须包含的三个组件:
//
// ① co_await:挂起协程,等待另一个awaitable完成
// ② co_yield:挂起并返回值(生成器模式)
// ③ co_return:返回值并结束协程

// 任意包含以上三个关键字的函数 = 协程函数
// 编译器自动将函数帧移到堆上(不再是栈帧)

// ② co_yield 实现生成器
#include 
#include 

struct Generator {
    struct promise_type {
        int current_value = 0;
        auto get_return_object() { return Generator{*this}; }
        auto initial_suspend() { return std::suspend_always{}; }
        auto final_suspend() noexcept { return std::suspend_always{}; }
        auto yield_value(int v) {
            current_value = v;
            return std::suspend_always{};  // 挂起点
        }
        void return_void() {}
        void unhandled_exception() { throw; }
    };

    using Handle = std::coroutine_handle;
    Handle coro_;

    explicit Generator(promise_type& p) : coro_(Handle::from_promise(p)) {}
    ~Generator() { if (coro_) coro_.destroy(); }

    int operator()() {
        if (!coro_.done()) coro_.resume();
        return coro_.promise().current_value;
    }
};

Generator fibonacci() {
    int a = 0, b = 1;
    while (true) {
        co_yield b;  // 返回当前值并挂起
        int next = a + b;
        a = b;
        b = next;
    }
}

int main() {
    auto gen = fibonacci();
    for (int i = 0; i < 10; i++) {
        std::cout << gen() << " ";  // 1 1 2 3 5 8 13 21 34 55
    }
}

二、异步Task的实现

2.1 基于libunifex的设计

// 完整的异步Task类型(简化版)
template
struct Task {
    struct promise_type {
        std::exception_ptr exception_;
        std::variant result_;
        bool started_ = false;

        auto get_return_object() {
            return Task{*this};
        }

        auto initial_suspend() {
            return std::suspend_always{};
        }

        auto final_suspend() noexcept {
            return std::suspend_always{};
        }

        void return_value(T val) {
            result_.template emplace<1>(std::move(val));
        }

        void unhandled_exception() {
            exception_ = std::current_exception();
            result_.template emplace<2>(exception_);
        }

        T get_result() {
            if (result_.index() == 2) {
                std::rethrow_exception(std::get<2>(result_));
            }
            return std::get<1>(result_);
        }
    };

    using Handle = std::coroutine_handle;
    Handle coro_;

    T get() { return coro_.promise().get_result(); }
};

// 异步sleep实现
struct AwaitableSleep {
    std::chrono::milliseconds duration_;
    bool ready_ = false;

    bool await_ready() { return false; }
    void await_suspend(std::coroutine_handle<> h) {
        std::thread([h, this] {
            std::this_thread::sleep_for(duration_);
            ready_ = true;
            h.resume();  // 恢复协程
        }).detach();
    }
    void await_resume() {}
};

Task async_work() {
    co_await AwaitableSleep{100ms};
    co_return 42;
}

int main() {
    auto task = async_work();
    std::cout << task.get();  // 打印42
}

三、协程的栈管理

// ⚠️ C++协程的核心陷阱:协程栈不是普通函数栈!
//
// 普通函数:栈向下增长,函数返回时栈自动清理
// 协程:协程帧在堆上,内存需要手动管理

// 问题1:局部变量的生命周期管理
Task<> bad_example() {
    auto conn = database.connect();  // ← 构造函数可能抛异常
    co_await conn.query("SELECT ..."); // conn如果在这里析构...
    // ...结果不可预测
}

// 问题2:避免引用悬挂
Task bad() {
    std::string local = "test";
    co_return local;  // ⚠️ 协程恢复时local已析构
}

// 解决:用std::shared_ptr或返回值

// 问题3:共享状态的所有权
// 协程可能比创建它的线程生命周期更长
// → 不能使用线程本地存储的引用
// → 需要显式传递所有权

// 最佳实践:协程中使用值语义
Task fetch_user(int id) {
    User user = co_await db.query_user(id);  // 值拷贝
    co_return user;  // 安全的返回值
}

// coroutine_handle的手动管理
void on_demand() {
    auto task = async_work();
    // 处理task...
    task.coro_.destroy();  // 手动销毁(必须!)

四、协程 vs 线程的对比

// 性能对比(10000个并发连接):
// 线程模型:10000线程 × 8MB栈 = 80GB内存 ❌不可行
// epoll+协程:10000协程 × 约1KB帧 = 10MB内存 ✅

// 适用场景对比:
// 协程:
//   ① IO密集(网络请求、文件读写)
//   ② 高并发连接(>1000)
//   ③ 需要高效上下文切换
//
// 线程:
//   ① CPU密集(计算密集型任务)
//   ② 需要真并行(利用多核)
//   ③ 简单明确的并发任务

// C++生态现状(2024):
// libunifex: Facebook开源,最完整的异步框架
// libasio: asio已支持C++20协程(推荐学习)
// C++23: std::generator, std::task(尚在提案阶段)

// C++23 std::generator(生成器,简化版)
#include 
std::generator fibonacci() {
    int a = 0, b = 1;
    while (true) {
        co_yield b;
        int next = a + b;
        a = b;
        b = next;
    }
}
// 使用:
for (int x : fibonacci() | std::views::take(10)) {
    std::cout << x << " ";
}