C++20协程不带调度器,需手动实现调度逻辑;co_await仅为挂起/恢复语法糖,不决定恢复时机与执行者;最简FIFO调度器需管理句柄存取与resume,并严格控制生命周期。
C++20 协程本身不带调度器,必须手动实现调度逻辑——这是所有初学者最容易误以为“协程自带线程/队列”的关键误区。
为什么不能直接 co_await 就自动跑起来?
因为 co_await 只是挂起/恢复的语法糖,它不决定“谁来恢复”“何时恢复”。编译器生成的状态机默认把控制权交还给调用者,而调用者(比如 main())通常不会主动去 resume 你。没有调度器,协程就只是个一动不动的句柄。
常见错误现象:
- 调用一个返回
task的协程函数后,程序立刻退出,什么都没打印 - 用
std::suspend_always{}挂起,但没人调用handle.resume(),协程永远卡住 - 多个协程注册进队列,但只 run 了一次就停了,没轮转
根本原因:C++20 协程是无栈、懒启动、完全用户控制的——调度器是你写的,不是语言给的。
立即学习“C++免费学习笔记(深入)”;
最简 FIFO 调度器怎么写?
核心就三件事:存句柄、取句柄、resume 句柄。不需要锁(单线程),也不需要复杂状态管理(初始/终挂起全设为 std::suspend_always)。
实操建议:
- 用
std::queue>存待执行协程 - 协程 promise_type 中,
initial_suspend()返回std::suspend_always{},确保创建后不自动执行 -
final_suspend()也返回std::suspend_always{},让协程结束时不销毁,方便调度器回收或判断完成 - 调度器
run()方法里循环pop + resume,并在 resume 后检查handle.done()决定是否丢弃
示例片段(promise_type 关键部分):