找回密码
 立即注册
首页 业界区 业界 没有调度器的协程不是好协程——零基础深入浅出 C++20 ...

没有调度器的协程不是好协程——零基础深入浅出 C++20 协程

冈欤寨 2025-9-26 10:59:06
前言

上一篇《协程本质是函数加状态机》谈到 C++20 协程的本质,是编译器基于 duff device 的精巧封装,经过一番乾坤大挪移,协程体内容被掉包只保留协程初始化代码,实际运行代码被包裹在编译器自动生成的 resume 函数中,这一点通过 C++ Insights 在线工具观察的一清二楚。
然而上一篇举的数列生成器例子中,协程的运行还是需要用户通过 while 循环来驱动,显得不够贴近实际,因此这一篇引入协程调度器,看看 C++20 协程是如何自动运行的,文章仍然遵守之前的创作原则:
* 选取合适的 demo 是头等大事
* 以协程为目标,涉及到的新语法会简单说明,不涉及的不旁征博引,很多新语法都是有了某种需求才创建的,理解这种需求本身比硬学语法规则更为重要
* 若语法的原理非常简单,也会简单展开讲讲,有利于透过现象看本质,用起来更得心应手
上一篇文章里不光探讨了协程的本质,还说明了一系列 C++20 协程概念:
* 协程体
* 协程状态
* 承诺对象
* 返回对象
* 协程句柄
及它们之间的关系:
1.png

并简单说明了接入 C++20 协程时用户需要实现的类型、接口、及其含义。如果没有这些内容铺垫,看本文时会有很多地方将会难以理解,还没看过的小伙伴,墙裂建议先看那篇。
工具还是之前介绍过的 C++ Insights 和 Compile Explorer,也在上一篇中介绍过了,这里不再赘述。
协程调度器

话不多说,直接上 demo:
[code]#include #include #include #include #include class SingleThreadScheduler {public:    void schedule(std::function task) {        tasks.push(std::move(task));    }    void run() {        while (!tasks.empty()) {            auto task = tasks.front();            tasks.pop();            task();          }    }private:    std::queue tasks;};struct AsyncTask {    struct promise_type {        AsyncTask get_return_object() {             return AsyncTask(std::coroutine_handle::from_promise(*this));         }        std::suspend_never initial_suspend() { return {}; }        std::suspend_always final_suspend() noexcept { return {}; }        void return_void() {}        void unhandled_exception() { std::terminate(); }    };    std::coroutine_handle handle;    explicit AsyncTask(std::coroutine_handle h) : handle(h) {}    ~AsyncTask() { if (handle) handle.destroy(); }};struct ScheduleAwaiter {    SingleThreadScheduler* scheduler;    bool await_ready() const { return false; }    void await_suspend(std::coroutine_handle h) {        scheduler->schedule([h] { h.resume(); });    }    void await_resume() {}};AsyncTask demo_coroutine(SingleThreadScheduler& scheduler, int id) {    std::cout

相关推荐

您需要登录后才可以回帖 登录 | 立即注册