协程调度器核心是std::coroutine_handle加就绪队列(如std::deque),通过run()循环取handle并resume;需在promise_type中控制initial_suspend和final_suspend为suspend_always,由await_suspend注册handle到队列,且必须显式destroy防泄漏。

协程任务调度器的核心结构怎么搭
直接用 std::coroutine_handle + 一个就绪队列(如 std::queue 或无锁队列)就能跑起来,不需要复杂框架。关键不是“实现协程”,而是“谁来 resume 它”——调度器本质就是个循环:取任务 → resume → 若挂起则放回队列或移交其他线程。
常见错误是把 co_await 当成自动调度开关,其实它只负责挂起/恢复,不触发调度逻辑。必须显式调用 handle.resume() 才算真正执行。
- 每个协程的 promise_type 需重载
get_return_object()返回封装了coroutine_handle的 task 类型 -
initial_suspend()通常返回suspend_always{},避免协程在创建后立即执行 -
final_suspend()必须返回suspend_always{},否则协程销毁时可能 crash(尤其当被多次 resume 后) - 不要在 promise 析构里调用
handle.destroy()—— handle 应由调度器统一管理生命周期
如何让协程在指定线程上恢复执行
默认情况下,resume() 在哪调用就在哪执行,但异步调度要求“提交到线程池、唤醒后在 worker 线程运行”。这就得靠 awaiter 控制恢复点。
典型做法是自定义 awaiter,在 await_ready() 返回 false 后,await_suspend() 中把 coroutine_handle 提交到目标线程的任务队列,并返回 false(表示不立即恢复)。
- 若用
std::thread池,需确保队列线程安全;推荐moodycamel::ConcurrentQueue或简易 spinlock queue - 别在
await_suspend()里直接调用resume(),否则失去调度意义 - 注意:Windows 上
GetThreadId(GetCurrentThread())和 Linux 的pthread_self()不可跨平台比较,应统一用调度器分配的 worker ID
怎样避免协程栈溢出和内存泄漏
协程帧(coroutine frame)默认在堆上分配,但如果不手动控制,容易在频繁创建/销毁任务时引发碎片或泄漏。C++20 没有内置协程内存池,得自己兜底。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
最简方案是在 promise_type 里重载 operator new / operator delete,绑定到预分配的内存块或 slab 分配器。
- 不要依赖全局 operator new —— 协程帧大小不确定,且不同编译器生成的帧布局可能不同
- 若使用
std::pmr::polymorphic_allocator,需确保所有 awaiter、promise、task 对象都用同一 memory resource - 泄漏高发点:未 resume 的协程 handle 持有帧地址却没 destroy;或 awaiter 持有 handle 但未在析构中判断是否已 resume
- 调试时加断点检查
handle.done() == false且未被 resume 过的任务,它们大概率泄露
为什么 std::jthread + co_await 配合不好
std::jthread 的 join 在析构时阻塞,而协程常在后台长期运行,若主线程退出前未显式 stop/join,会导致未定义行为甚至死锁。
更严重的是:jthread 内部用 std::stop_token,但协程 suspend 点未必响应 stop —— 它不是信号量,不会自动中断挂起状态。
- 正确做法:用自定义 stoppable_awaiter,其
await_suspend()注册回调到 stop_source,挂起前检查stop_token.stop_requested() - 别把 jthread 当“协程运行载体”,它只是带自动 join 的 thread;协程调度应独立于线程生命周期
- 生产环境建议用
std::thread+ 显式管理,或基于 io_uring(Linux)/ IOCP(Windows)的事件驱动模型,避免线程与协程耦合过紧
协程调度器最难的部分从来不是语法,而是资源归属边界——谁 alloc,谁 free,谁 resume,谁 cancel。这些责任一旦模糊,问题就会在压测时集中爆发。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










