没有调度器的协程不是好协程——零基础深入浅出 C++20 协程
前言上一篇《协程本质是函数加状态机》谈到 C++20 协程的本质,是编译器基于 duff device 的精巧封装,经过一番乾坤大挪移,协程体内容被掉包只保留协程初始化代码,实际运行代码被包裹在编译器自动生成的 resume 函数中,这一点通过 C++ Insights 在线工具观察的一清二楚。
然而上一篇举的数列生成器例子中,协程的运行还是需要用户通过 while 循环来驱动,显得不够贴近实际,因此这一篇引入协程调度器,看看 C++20 协程是如何自动运行的,文章仍然遵守之前的创作原则:
* 选取合适的 demo 是头等大事
* 以协程为目标,涉及到的新语法会简单说明,不涉及的不旁征博引,很多新语法都是有了某种需求才创建的,理解这种需求本身比硬学语法规则更为重要
* 若语法的原理非常简单,也会简单展开讲讲,有利于透过现象看本质,用起来更得心应手
上一篇文章里不光探讨了协程的本质,还说明了一系列 C++20 协程概念:
* 协程体
* 协程状态
* 承诺对象
* 返回对象
* 协程句柄
及它们之间的关系:
并简单说明了接入 C++20 协程时用户需要实现的类型、接口、及其含义。如果没有这些内容铺垫,看本文时会有很多地方将会难以理解,还没看过的小伙伴,墙裂建议先看那篇。
工具还是之前介绍过的 C++ Insights 和 Compile Explorer,也在上一篇中介绍过了,这里不再赘述。
协程调度器
话不多说,直接上 demo:
#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.resume(); }); } void await_resume() {}};AsyncTask demo_coroutine(SingleThreadScheduler& scheduler, int id) { std::cout
页:
[1]