协程是用户态可挂起恢复的函数,C++20采用无栈协程,编译器将其重写为状态机;需含co_await/co_yield/co_return之一,返回类型须定义promise_type以支持协程协议。

协程不是线程,也不依赖操作系统调度;它是用户态的、可挂起和恢复的函数,适合写异步 I/O、生成器、状态机等逻辑清晰但传统回调写法容易嵌套过深的场景。C++20 的协程是无栈协程(stackless),编译器会将协程函数重写为状态机,由你控制内存布局和执行时机。
第一步:识别协程函数——三个关键字缺一不可
一个函数要成为协程,必须在函数体中至少出现以下任一关键词:
- co_await:等待某个“可等待对象”(如自定义 awaiter、std::suspend_always)
- co_yield:产出值并挂起,常用于生成器
- co_return:结束协程(可能触发清理或回调)
只要用了其中一个,编译器就按协程处理——自动改写函数签名、生成 promise 对象、管理状态机。注意:函数返回类型必须满足特定要求(见下一步)。
第二步:返回类型需支持协程协议——关键在 promise_type
协程函数的返回类型(比如 Generator
立即学习“C++免费学习笔记(深入)”;
- get_return_object():返回协程句柄(如 Generator 实例),供调用者接收
- initial_suspend():决定协程启动时是否立刻挂起(常返回 std::suspend_always 或 std::suspend_never)
- final_suspend():协程结束前是否挂起(影响资源释放时机)
- unhandled_exception():捕获未处理异常
- return_void() / return_value(T):对应 co_return 的不同写法
标准库没提供通用协程类型,你需要自己定义(或使用第三方如 cppcoro)。初学建议从简单生成器入手。
《PHP设计模式》首先介绍了设计模式,讲述了设计模式的使用及重要性,并且详细说明了应用设计模式的场合。接下来,本书通过代码示例介绍了许多设计模式。最后,本书通过全面深入的案例分析说明了如何使用设计模式来计划新的应用程序,如何采用PHP语言编写这些模式,以及如何使用书中介绍的设计模式修正和重构已有的代码块。作者采用专业的、便于使用的格式来介绍相关的概念,自学成才的编程人员与经过更多正规培训的编程人员
第三步:动手写一个整数生成器(Generator)
下面是最小可行示例,实现一个每次调用 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 —— 自定义 awaiter 的核心三接口
当你写 co_await expr,expr 类型需提供:
- await_ready():返回 bool,true 表示无需挂起,直接继续
- await_suspend(handle):挂起时调用,可安排 handle 在未来某时 resume(例如投递到线程池、注册到 epoll)
- await_resume():resume 后返回给 co_await 表达式的值
这是实现异步 I/O 的入口。例如封装一个 sleep_for awaiter,内部用 std::thread::sleep_for + std::jthread 或定时器唤醒 handle,就能写出 co_await sleep_for(500ms) 这样的代码。
不复杂但容易忽略:协程对象的内存必须手动管理(或用智能指针包装 handle),且 promise 对象默认分配在协程帧中(栈上),若需跨 suspend 持久化,得重载 operator new 做堆分配。









