{"id":8646,"date":"2023-11-27T12:49:19","date_gmt":"2023-11-27T12:49:19","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=8646"},"modified":"2023-11-27T12:49:19","modified_gmt":"2023-11-27T12:49:19","slug":"a-priority-scheduler-for-coroutines","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/a-priority-scheduler-for-coroutines\/","title":{"rendered":"A Priority Scheduler for Coroutines"},"content":{"rendered":"\n<p>In this post, I will extend the straightforward scheduler from Dian-Lun with priorities.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1030\" height=\"369\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/TimelineCpp20-1030x369.png\" alt=\"\" class=\"wp-image-8607\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/TimelineCpp20-1030x369.png 1030w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/TimelineCpp20-300x108.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/TimelineCpp20-768x275.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/TimelineCpp20-705x253.png 705w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/TimelineCpp20.png 1068w\" sizes=\"auto, (max-width: 1030px) 100vw, 1030px\" \/><\/figure>\n\n\n\n<p>This is the third post in my mini-series about schedulers for C++ coroutines. The first two posts were guest posts by Dian-Lun Lin:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.modernescpp.com\/index.php\/a-concise-introduction-to-coroutines-by-dian-lun-li\/\" data-type=\"link\" data-id=\"https:\/\/www.modernescpp.com\/index.php\/a-concise-introduction-to-coroutines-by-dian-lun-li\/\">A Concise Introduction to Coroutines by Dian-Lun Lin<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.modernescpp.com\/index.php\/coroutines-a-scheduler-for-tasks-by-dian-lun-li\/\" data-type=\"link\" data-id=\"https:\/\/www.modernescpp.com\/index.php\/coroutines-a-scheduler-for-tasks-by-dian-lun-li\/\">Coroutines: A Scheduler for Tasks by Dian-Lun Lin<\/a><\/li>\n<\/ul>\n\n\n\n<p>Dian-Lun&#8217;s schedulers were based on the container adaptor <code><a href=\"https:\/\/en.cppreference.com\/w\/cpp\/container\/stack\">std::stack<\/a><\/code> and <code><a href=\"https:\/\/en.cppreference.com\/w\/cpp\/container\/queue\">std::queue<\/a><\/code>. The <code>std::stack<\/code> schedules its tasks according to its strategy last-in first-out, but the<code> std::queue<\/code> applies first-in first-out. <\/p>\n\n\n\n<p>The following code snippet shows the queue-based scheduler: <\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">Scheduler<\/span> {\n\n  std<span style=\"color: #555555\">::<\/span>queue<span style=\"color: #555555\">&lt;<\/span>std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;&gt;&gt;<\/span> _tasks;\n\n  <span style=\"color: #9999FF\">public:<\/span> \n\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> <span style=\"color: #CC00FF\">emplace<\/span>(std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;&gt;<\/span> task) {\n      _tasks.push(task);\n    }\n\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> <span style=\"color: #CC00FF\">schedule<\/span>() {\n      <span style=\"color: #006699; font-weight: bold\">while<\/span>(<span style=\"color: #555555\">!<\/span>_tasks.empty()) {\n        <span style=\"color: #006699; font-weight: bold\">auto<\/span> task <span style=\"color: #555555\">=<\/span> _tasks.front();\n        _tasks.pop();\n        task.resume();\n\n        <span style=\"color: #006699; font-weight: bold\">if<\/span>(<span style=\"color: #555555\">!<\/span>task.done()) { \n          _tasks.push(task);\n        }\n        <span style=\"color: #006699; font-weight: bold\">else<\/span> {\n          task.destroy();\n        }\n      }\n    }\n\n    <span style=\"color: #006699; font-weight: bold\">auto<\/span> <span style=\"color: #CC00FF\">suspend<\/span>() {\n      <span style=\"color: #006699; font-weight: bold\">return<\/span> std<span style=\"color: #555555\">::<\/span>suspend_always{};\n    }\n};\n<\/pre><\/div>\n\n\n\n<p>Extending this scheduler with priorities is pretty straightforward.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Priority-Queue based Scheduler<\/h2>\n\n\n\n<p><code><a href=\"https:\/\/en.cppreference.com\/w\/cpp\/container\/priority_queue\">std::priority_queue<\/a><\/code> is besides <code>std::stack<\/code>, and<code> std::queue<\/code> the third container adaptor in C++98.<\/p>\n\n\n\n<p>The <code>std::priority_queue<\/code> is a similar to a<code> std::queue<\/code>.  The main difference to the <code>std::queue<\/code> is that their greatest element is always at the top of the priority queue. <code>std::priority_queue<\/code> uses by default the comparison operator <code>std::less<\/code>. The lookup time into a <code>std::priority_queue <\/code>is constant, but the insertion and extraction are logarithmic.<\/p>\n\n\n\n<p>Let me exchange the <code>std::queue<\/code> in the previous scheduler with a <code>std::priority_queue<\/code>:<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #0099FF; font-style: italic\">\/\/ priority_queueScheduler.cpp<\/span>\n\n<span style=\"color: #009999\">#include &lt;coroutine&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;queue&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;utility&gt;<\/span>\n\n\n<span style=\"color: #006699; font-weight: bold\">struct<\/span> Task {\n\n  <span style=\"color: #006699; font-weight: bold\">struct<\/span> promise_type {\n    std<span style=\"color: #555555\">::<\/span>suspend_always initial_suspend() noexcept { <span style=\"color: #006699; font-weight: bold\">return<\/span> {}; }\n    std<span style=\"color: #555555\">::<\/span>suspend_always final_suspend() noexcept { <span style=\"color: #006699; font-weight: bold\">return<\/span> {}; }\n\n    Task get_return_object() { \n        <span style=\"color: #006699; font-weight: bold\">return<\/span> std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;<\/span>promise_type<span style=\"color: #555555\">&gt;::<\/span>from_promise(<span style=\"color: #555555\">*<\/span><span style=\"color: #006699; font-weight: bold\">this<\/span>); \n    }\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> return_void() {}\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> unhandled_exception() {}\n  };\n\n  Task(std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;<\/span>promise_type<span style=\"color: #555555\">&gt;<\/span> handle)<span style=\"color: #555555\">:<\/span> handle{handle}{}\n\n  <span style=\"color: #006699; font-weight: bold\">auto<\/span> get_handle() { <span style=\"color: #006699; font-weight: bold\">return<\/span> handle; }\n\n  std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;<\/span>promise_type<span style=\"color: #555555\">&gt;<\/span> handle;\n};\n\n<span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">Scheduler<\/span> {\n                                                            <span style=\"color: #0099FF; font-style: italic\">\/\/ (1)<\/span>\n  std<span style=\"color: #555555\">::<\/span>priority_queue<span style=\"color: #555555\">&lt;<\/span>std<span style=\"color: #555555\">::<\/span>pair<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span>, std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;&gt;&gt;&gt;<\/span> _prioTasks;\n\n  <span style=\"color: #9999FF\">public:<\/span> \n\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> <span style=\"color: #CC00FF\">emplace<\/span>(<span style=\"color: #007788; font-weight: bold\">int<\/span> prio, std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;&gt;<\/span> task) {   <span style=\"color: #0099FF; font-style: italic\">\/\/ (2)<\/span>\n      _prioTasks.push(std<span style=\"color: #555555\">::<\/span>make_pair(prio, task));\n    }\n\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> <span style=\"color: #CC00FF\">schedule<\/span>() {\n      <span style=\"color: #006699; font-weight: bold\">while<\/span>(<span style=\"color: #555555\">!<\/span>_prioTasks.empty()) {                           <span style=\"color: #0099FF; font-style: italic\">\/\/ (3)<\/span>\n        <span style=\"color: #006699; font-weight: bold\">auto<\/span> [prio, task] <span style=\"color: #555555\">=<\/span> _prioTasks.top();\n        _prioTasks.pop();\n        task.resume();\n\n        <span style=\"color: #006699; font-weight: bold\">if<\/span>(<span style=\"color: #555555\">!<\/span>task.done()) { \n          _prioTasks.push(std<span style=\"color: #555555\">::<\/span>make_pair(prio, task));        <span style=\"color: #0099FF; font-style: italic\">\/\/ (4)<\/span>\n        }\n        <span style=\"color: #006699; font-weight: bold\">else<\/span> {\n          task.destroy();\n        }\n      }\n    }\n\n    <span style=\"color: #006699; font-weight: bold\">auto<\/span> <span style=\"color: #CC00FF\">suspend<\/span>() {\n      <span style=\"color: #006699; font-weight: bold\">return<\/span> std<span style=\"color: #555555\">::<\/span>suspend_always{};\n    }\n};\n\n\nTask <span style=\"color: #CC00FF\">TaskA<\/span>(Scheduler<span style=\"color: #555555\">&amp;<\/span> sch) {\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Hello from TaskA<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n  co_await sch.suspend();\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Executing the TaskA<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n  co_await sch.suspend();\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;TaskA is finished<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n}\n\nTask <span style=\"color: #CC00FF\">TaskB<\/span>(Scheduler<span style=\"color: #555555\">&amp;<\/span> sch) {\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Hello from TaskB<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n  co_await sch.suspend();\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Executing the TaskB<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n  co_await sch.suspend();\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;TaskB is finished<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n}\n\n\n<span style=\"color: #007788; font-weight: bold\">int<\/span> <span style=\"color: #CC00FF\">main<\/span>() {\n\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n\n  Scheduler scheduler1;\n\n  scheduler1.emplace(<span style=\"color: #FF6600\">0<\/span>, TaskA(scheduler1).get_handle());       <span style=\"color: #0099FF; font-style: italic\">\/\/ (5)   <\/span>\n  scheduler1.emplace(<span style=\"color: #FF6600\">1<\/span>, TaskB(scheduler1).get_handle());\n\n  scheduler1.schedule();\n\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n\n  Scheduler scheduler2;\n\n  scheduler2.emplace(<span style=\"color: #FF6600\">1<\/span>, TaskA(scheduler2).get_handle());      <span style=\"color: #0099FF; font-style: italic\">\/\/ (6)<\/span>\n  scheduler2.emplace(<span style=\"color: #FF6600\">0<\/span>, TaskB(scheduler2).get_handle());\n\n  scheduler2.schedule();\n\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n\n}\n<\/pre><\/div>\n\n\n\n<p>First, the <code>std::priority_queue<\/code> uses a pair (priority, handle) (line 1). Now, this pair is placed on the <code>_prioTask<\/code> (line 2). When the scheduler runs, it checks if the <code>_prioTask<\/code> is empty (line 3). If not, the first task is accessed, removed, and resumed. When the task is not done, it is pushed back onto the <code>_prioTasks<\/code> (line 4).<\/p>\n\n\n\n<p>Using a<code> std::priority_queue&lt;std::pair&lt;int, std::coroutine_handle&lt;&gt;&gt;&gt;<\/code>  has the nice side-effect, that tasks with higher priority run first. It makes no difference, in which order the tasks are placed on the scheduler (lines 5 and 6); the task with priority 1 runs first. <\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"435\" height=\"452\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueScheduler.png\" alt=\"\" class=\"wp-image-8660\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueScheduler.png 435w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueScheduler-289x300.png 289w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueScheduler-36x36.png 36w\" sizes=\"auto, (max-width: 435px) 100vw, 435px\" \/><\/figure>\n\n\n\n<p>Let me simplify the coroutine, before I improve its priority handling in my next post.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Simplified Coroutine<\/h3>\n\n\n\n<p>Here are the previous coroutines <code>TaskA <\/code>and <code>TaskB<\/code>: <\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\">Task <span style=\"color: #CC00FF\">TaskA<\/span>(Scheduler<span style=\"color: #555555\">&amp;<\/span> sch) {\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Hello from TaskA<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n  co_await sch.suspend();\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Executing the TaskA<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n  co_await sch.suspend();\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;TaskA is finished<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n}\n\nTask <span style=\"color: #CC00FF\">TaskB<\/span>(Scheduler<span style=\"color: #555555\">&amp;<\/span> sch) {\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Hello from TaskB<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n  co_await sch.suspend();\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Executing the TaskB<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n  co_await sch.suspend();\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;TaskB is finished<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n}\n<\/pre><\/div>\n\n\n\n<p>First, instead of calling <code>co_await<\/code> on the scheduler, I replace it with the direct call of the predefined awaitable <code>std::suspend_always<\/code>. This allows me to remove the <code>suspend <\/code>member function of the scheduler. Second, the coroutine gets the name of its task:<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\">Task <span style=\"color: #CC00FF\">createTask<\/span>(<span style=\"color: #006699; font-weight: bold\">const<\/span> std<span style=\"color: #555555\">::<\/span>string<span style=\"color: #555555\">&amp;<\/span> name) {\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> name <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot; start<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n  co_await std<span style=\"color: #555555\">::<\/span>suspend_always();\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> name <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot; execute<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n  co_await std<span style=\"color: #555555\">::<\/span>suspend_always();\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> name <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot; finish<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n}\n<\/pre><\/div>\n\n\n\n<p>Finally, here is the simplified program with the corresponding output.<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #0099FF; font-style: italic\">\/\/ priority_queueSchedulerSimplified.cpp<\/span>\n\n<span style=\"color: #009999\">#include &lt;coroutine&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;queue&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;utility&gt;<\/span>\n\n\n<span style=\"color: #006699; font-weight: bold\">struct<\/span> Task {\n\n  <span style=\"color: #006699; font-weight: bold\">struct<\/span> promise_type {\n    std<span style=\"color: #555555\">::<\/span>suspend_always initial_suspend() noexcept { <span style=\"color: #006699; font-weight: bold\">return<\/span> {}; }\n    std<span style=\"color: #555555\">::<\/span>suspend_always final_suspend() noexcept { <span style=\"color: #006699; font-weight: bold\">return<\/span> {}; }\n\n    Task get_return_object() { \n        <span style=\"color: #006699; font-weight: bold\">return<\/span> std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;<\/span>promise_type<span style=\"color: #555555\">&gt;::<\/span>from_promise(<span style=\"color: #555555\">*<\/span><span style=\"color: #006699; font-weight: bold\">this<\/span>); \n    }\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> return_void() {}\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> unhandled_exception() {}\n  };\n\n  Task(std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;<\/span>promise_type<span style=\"color: #555555\">&gt;<\/span> handle)<span style=\"color: #555555\">:<\/span> handle{handle}{}\n\n  <span style=\"color: #006699; font-weight: bold\">auto<\/span> get_handle() { <span style=\"color: #006699; font-weight: bold\">return<\/span> handle; }\n\n  std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;<\/span>promise_type<span style=\"color: #555555\">&gt;<\/span> handle;\n};\n\n<span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">Scheduler<\/span> {\n\n  std<span style=\"color: #555555\">::<\/span>priority_queue<span style=\"color: #555555\">&lt;<\/span>std<span style=\"color: #555555\">::<\/span>pair<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span>, std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;&gt;&gt;&gt;<\/span> _prioTasks;\n\n  <span style=\"color: #9999FF\">public:<\/span> \n\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> <span style=\"color: #CC00FF\">emplace<\/span>(<span style=\"color: #007788; font-weight: bold\">int<\/span> prio, std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;&gt;<\/span> task) {\n      _prioTasks.push(std<span style=\"color: #555555\">::<\/span>make_pair(prio, task));\n    }\n\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> <span style=\"color: #CC00FF\">schedule<\/span>() {\n      <span style=\"color: #006699; font-weight: bold\">while<\/span>(<span style=\"color: #555555\">!<\/span>_prioTasks.empty()) {\n        <span style=\"color: #006699; font-weight: bold\">auto<\/span> [prio, task] <span style=\"color: #555555\">=<\/span> _prioTasks.top();\n        _prioTasks.pop();\n        task.resume();\n\n        <span style=\"color: #006699; font-weight: bold\">if<\/span>(<span style=\"color: #555555\">!<\/span>task.done()) { \n          _prioTasks.push(std<span style=\"color: #555555\">::<\/span>make_pair(prio, task));\n        }\n        <span style=\"color: #006699; font-weight: bold\">else<\/span> {\n          task.destroy();\n        }\n      }\n    }\n\n};\n\n\nTask <span style=\"color: #CC00FF\">createTask<\/span>(<span style=\"color: #006699; font-weight: bold\">const<\/span> std<span style=\"color: #555555\">::<\/span>string<span style=\"color: #555555\">&amp;<\/span> name) {\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> name <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot; start<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n  co_await std<span style=\"color: #555555\">::<\/span>suspend_always();\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> name <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot; execute<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n  co_await std<span style=\"color: #555555\">::<\/span>suspend_always();\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> name <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot; finish<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n}\n\n\n<span style=\"color: #007788; font-weight: bold\">int<\/span> <span style=\"color: #CC00FF\">main<\/span>() {\n\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n\n  Scheduler scheduler1;\n\n  scheduler1.emplace(<span style=\"color: #FF6600\">0<\/span>, createTask(<span style=\"color: #CC3300\">&quot;TaskA&quot;<\/span>).get_handle());\n  scheduler1.emplace(<span style=\"color: #FF6600\">1<\/span>, createTask(<span style=\"color: #CC3300\">&quot;  TaskB&quot;<\/span>).get_handle());\n\n  scheduler1.schedule();\n\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n\n  Scheduler scheduler2;\n\n  scheduler2.emplace(<span style=\"color: #FF6600\">1<\/span>, createTask(<span style=\"color: #CC3300\">&quot;TaskA&quot;<\/span>).get_handle());\n  scheduler2.emplace(<span style=\"color: #FF6600\">0<\/span>, createTask(<span style=\"color: #CC3300\">&quot;  TaskB&quot;<\/span>).get_handle());\n\n  scheduler2.schedule();\n\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n\n}\n<\/pre><\/div>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"546\" height=\"453\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueSchedulerSimplifiied.png\" alt=\"\" class=\"wp-image-8664\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueSchedulerSimplifiied.png 546w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueSchedulerSimplifiied-300x249.png 300w\" sizes=\"auto, (max-width: 546px) 100vw, 546px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">What&#8217;s Next? <\/h2>\n\n\n\n<p>In my next post, I will improve the priority handling of the tasks.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post, I will extend the straightforward scheduler from Dian-Lun with priorities. This is the third post in my mini-series about schedulers for C++ coroutines. The first two posts were guest posts by Dian-Lun Lin: Dian-Lun&#8217;s schedulers were based on the container adaptor std::stack and std::queue. The std::stack schedules its tasks according to its [&hellip;]<\/p>\n","protected":false},"author":21,"featured_media":8607,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[445],"class_list":["post-8646","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-coroutines"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8646","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=8646"}],"version-history":[{"count":22,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8646\/revisions"}],"predecessor-version":[{"id":8745,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8646\/revisions\/8745"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/8607"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=8646"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=8646"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=8646"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}