C++20协程由返回类型、promise_type和coroutine_handle组成,通过co_await/co_yield/co_return触发,编译器将其转为状态机,实现暂停与恢复。

在C++20中,协程不再是第三方库的专属功能,而是语言原生支持的特性。它允许函数在执行过程中暂停并恢复,而无需阻塞线程。要理解如何实现一个简单的协程,需要先掌握C++20协程的基本结构和核心组件。
协程的三个基本组成部分
C++20协程依赖于三个关键部分:返回类型、promise_type 和协程句柄(coroutine_handle)。只有满足这些条件,编译器才会将函数识别为协程。
- 返回类型:必须包含嵌套的 promise_type 类型。
- promise_type:定义协程的行为,比如初始挂起、最终挂起、返回值处理等。
- 协程句柄 coroutine_handle:用于手动控制协程的暂停与恢复。
当函数中出现 co_await、co_yield 或 co_return 关键字时,该函数自动成为协程。
实现一个最简单的协程
下面是一个极简但完整的协程示例,展示如何定义一个可挂起并恢复的协程:
立即学习“C++免费学习笔记(深入)”;
#include#include struct SimpleCoroutine { struct promise_type { SimpleCoroutine get_return_object() { return {}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() {} }; }; SimpleCoroutine hello_coroutine() { std::cout << "Hello from coroutine!\n"; co_await std::suspend_always{}; }
这个例子中:
- SimpleCoroutine::promise_type 提供了协程所需的所有接口。
- initial_suspend 返回 std::suspend_always,表示协程启动后立即挂起。
- final_suspend 同样挂起,防止协程结束后自动销毁。
- co_await std::suspend_always{} 显式挂起点。
手动控制协程的生命周期
使用 std::coroutine_handle 可以获取对协程状态的直接控制:
int main() {
auto coro = hello_coroutine();
// 获取协程句柄(需修改返回对象传递 handle)
// 实际中通常在 get_return_object 中构造 handle
return 0;
}
更实用的做法是让返回类型持有 coroutine_handle:
struct Task {
struct promise_type;
using handle_type = std::coroutine_handle;
struct promise_type {
Task get_return_object() {
return Task(handle_type::from_promise(*this));
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
handle_type h_;
explicit Task(handle_type h) : h_(h) {}
~Task() { if (h_) h_.destroy(); }
void resume() { if (h_ && !h_.done()) h_.resume(); }
};
这样就可以在外部调用 resume 来恢复执行:
Task my_coroutine() {
std::cout << "Start\n";
co_await std::suspend_always{};
std::cout << "Resumed!\n";
}
int main() {
Task t = my_coroutine();
t.resume(); // 输出 "Start"
t.resume(); // 输出 "Resumed!"
}
协程的工作原理简析
C++20协程在编译期被转换成状态机。编译器会将协程拆分为多个帧(frame),其中包含局部变量、当前状态和挂起点信息。
- 每次调用 co_await 时,会检查是否需要挂起(via await_ready)。
- 若需挂起,则执行 await_suspend(可传入 coroutine_handle)来安排恢复时机。
- 通过 await_resume 获取结果。
标准提供了 std::suspend_always 和 std::suspend_never 两种默认awaiter,分别表示总是挂起和从不挂起。
基本上就这些。C++20协程机制灵活但底层,实际使用常配合生成器、异步任务等模式封装。理解其组成和生命周期是构建高效异步程序的基础。











