协程是用户态可挂起恢复的函数,C++20采用无栈协程,编译器将其重写为状态机;需含co_await/co_yield/co_return之一,返回类型须定义promise_type以支持协程协议。
协程不是线程,也不依赖操作系统调度;它是用户态的、可挂起和恢复的函数,适合写异步 I/O、生成器、状态机等逻辑清晰但传统回调写法容易嵌套过深的场景。C++20 的协程是无栈协程(stackless),编译器会将协程函数重写为状态机,由你控制内存布局和执行时机。
一个函数要成为协程,必须在函数体中至少出现以下任一关键词:
只要用了其中一个,编译器就按协程处理——自动改写函数签名、生成 promise 对象、管理状态机。注意:函数返回类型必须满足特定要求(见下一步)。
协程函数的返回类型(比如 Generator
标准库没提供通用协程类型,你需要自己定义(或使用第三方如 cppcoro)。初学建议从简单生成器入手。
下面是最小可行示例,实现一个每次调用 next() 返回下一个斐波那契数的协程:
templateclass Generator { struct promise_type; using handle_type = std::coroutine_handle handle_type h_; public: Generator(handle_type h) : h_(h) {} Generator(Generator&& g) noexcept : h_(std::exchange(g.h_, {})) {} ~Generator() { if (h_) h_.destroy(); } T next() { h_.resume(); return h_.promise().current_value; } struct promise_type { T current_value; std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } Generator get_return_object() { return Generator{handle_type::from_promise(*this)}; } void return_void() {} void unhandled_exception() { std::terminate(); } std::suspend_always yield_value(T value) { current_value = value; return {}; } }; }; // 协程函数 Generator fibonacci() { int a = 0, b = 1; co_yield a; co_yield b; while (true) { int next = a + b; co_yield next; a = b; b = next; } }
使用方式:
auto gen = fibonacci();
for (int i = 0; i < 10; ++i) {
std::cout << gen.next() << " "; // 输出前10个斐波那契数
}
当你写 co_await expr,expr 类型需提供:
这是实现异步 I/O 的入口。例如封装一个 sleep_for awaiter,内部用 std::thread::sleep_for + std::jthread 或定时器唤醒 handle,就能写出 co_await sleep_for(500ms) 这样的代码。
不复杂但容易忽略:协程对象的内存必须手动管理(或用智能指针包装 handle),且 promise 对象默认分配在协程帧中(栈上),若需跨 suspend 持久
化,得重载 operator new 做堆分配。