{"id":8779,"date":"2023-12-11T11:30:56","date_gmt":"2023-12-11T11:30:56","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=8779"},"modified":"2023-12-11T11:42:16","modified_gmt":"2023-12-11T11:42:16","slug":"a-bug-in-the-priority-scheduler-for-coroutines","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/a-bug-in-the-priority-scheduler-for-coroutines\/","title":{"rendered":"A Bug in the Priority Scheduler for Coroutines"},"content":{"rendered":"\n<p>In my last two posts, I presented priority schedulers for coroutines. The schedulers had a bug.<\/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\/12\/TimelineCpp20-1030x369.png\" alt=\"\" class=\"wp-image-8780\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/TimelineCpp20-1030x369.png 1030w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/TimelineCpp20-300x108.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/TimelineCpp20-768x275.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/TimelineCpp20-705x253.png 705w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/TimelineCpp20.png 1068w\" sizes=\"auto, (max-width: 1030px) 100vw, 1030px\" \/><\/figure>\n\n\n\n<p>First of all, here is the erroneous 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: #0099FF; font-style: italic\">\/\/ priority_queueSchedulerPriority.cpp<\/span>\n\n<span style=\"color: #009999\">#include &lt;concepts&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;coroutine&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;functional&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\">using<\/span> job <span style=\"color: #555555\">=<\/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;<\/span>;\n\n<span style=\"color: #006699; font-weight: bold\">template<\/span> <span style=\"color: #555555\">&lt;<\/span><span style=\"color: #006699; font-weight: bold\">typename<\/span> Updater <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>identity,                         <span style=\"color: #0099FF; font-style: italic\">\/\/ (1)<\/span>\n          <span style=\"color: #006699; font-weight: bold\">typename<\/span> Comperator <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>ranges<span style=\"color: #555555\">::<\/span>less<span style=\"color: #555555\">&gt;<\/span>                   \nrequires std<span style=\"color: #555555\">::<\/span>invocable<span style=\"color: #555555\">&lt;<\/span>decltype(Updater()), <span style=\"color: #007788; font-weight: bold\">int<\/span><span style=\"color: #555555\">&gt;<\/span> <span style=\"color: #555555\">&amp;&amp;<\/span>                <span style=\"color: #0099FF; font-style: italic\">\/\/ (2)<\/span>\n         std<span style=\"color: #555555\">::<\/span>predicate<span style=\"color: #555555\">&lt;<\/span>decltype(Comperator()), job, job<span style=\"color: #555555\">&gt;<\/span>             \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>job, std<span style=\"color: #555555\">::<\/span>vector<span style=\"color: #555555\">&lt;<\/span>job<span style=\"color: #555555\">&gt;<\/span>, Comperator<span style=\"color: #555555\">&gt;<\/span> _prioTasks;\n\n  <span style=\"color: #9999FF\">public:<\/span> \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      Updater upd <span style=\"color: #555555\">=<\/span> {};                                            <span style=\"color: #0099FF; font-style: italic\">\/\/ (3)<\/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(upd(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};\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  <span style=\"color: #006699; font-weight: bold\">for<\/span> (<span style=\"color: #007788; font-weight: bold\">int<\/span> i <span style=\"color: #555555\">=<\/span> <span style=\"color: #FF6600\">0<\/span>; i <span style=\"color: #555555\">&lt;=<\/span> <span style=\"color: #FF6600\">3<\/span>; <span style=\"color: #555555\">++<\/span>i ) { \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 &quot;<\/span> <span style=\"color: #555555\">&lt;&lt;<\/span> i <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;                  <span style=\"color: #0099FF; font-style: italic\">\/\/ (5)<\/span>\n    co_await std<span style=\"color: #555555\">::<\/span>suspend_always();\n  }\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;                                               <span style=\"color: #0099FF; font-style: italic\">\/\/ (6)<\/span>\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  scheduler1.emplace(<span style=\"color: #FF6600\">2<\/span>, createTask(<span style=\"color: #CC3300\">&quot;    TaskC&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<span style=\"color: #555555\">&lt;<\/span>decltype([](<span style=\"color: #007788; font-weight: bold\">int<\/span> a) { <span style=\"color: #006699; font-weight: bold\">return<\/span> a <span style=\"color: #555555\">-<\/span> <span style=\"color: #FF6600\">1<\/span>; })<span style=\"color: #555555\">&gt;<\/span> scheduler2;        <span style=\"color: #0099FF; font-style: italic\">\/\/ (7)<\/span>\n\n  scheduler2.emplace(<span style=\"color: #FF6600\">0<\/span>, createTask(<span style=\"color: #CC3300\">&quot;TaskA&quot;<\/span>).get_handle());\n  scheduler2.emplace(<span style=\"color: #FF6600\">1<\/span>, createTask(<span style=\"color: #CC3300\">&quot;  TaskB&quot;<\/span>).get_handle());\n  scheduler2.emplace(<span style=\"color: #FF6600\">2<\/span>, createTask(<span style=\"color: #CC3300\">&quot;    TaskC&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\n<p>This is the output of the program I got.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"743\" height=\"937\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueSchedulerUpdatePriority.png\" alt=\"\" class=\"wp-image-8683\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueSchedulerUpdatePriority.png 743w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueSchedulerUpdatePriority-238x300.png 238w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueSchedulerUpdatePriority-559x705.png 559w\" sizes=\"auto, (max-width: 743px) 100vw, 743px\" \/><\/figure>\n\n\n\n<p>Christof Meerwald got another output with GCC. Thanks a lot for letting me know. Here is the GCC output with optimization enabled. <\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"632\" height=\"939\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/bugScheduler.png\" alt=\"\" class=\"wp-image-8782\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/bugScheduler.png 632w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/bugScheduler-202x300.png 202w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/bugScheduler-475x705.png 475w\" sizes=\"auto, (max-width: 632px) 100vw, 632px\" \/><\/figure>\n\n\n\n<p>Similarly, the Windows output was also broken:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"574\" height=\"856\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/bugSchedulerWindows.png\" alt=\"\" class=\"wp-image-8783\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/bugSchedulerWindows.png 574w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/bugSchedulerWindows-201x300.png 201w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/12\/bugSchedulerWindows-473x705.png 473w\" sizes=\"auto, (max-width: 574px) 100vw, 574px\" \/><\/figure>\n\n\n\n<p>Can you spot the error? Here are the crucial lines:<\/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) {                      <span style=\"color: #0099FF; font-style: italic\">\/\/ (1)<\/span>\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  <span style=\"color: #006699; font-weight: bold\">for<\/span> (<span style=\"color: #007788; font-weight: bold\">int<\/span> i <span style=\"color: #555555\">=<\/span> <span style=\"color: #FF6600\">0<\/span>; i <span style=\"color: #555555\">&lt;=<\/span> <span style=\"color: #FF6600\">3<\/span>; <span style=\"color: #555555\">++<\/span>i ) { \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 &quot;<\/span> <span style=\"color: #555555\">&lt;&lt;<\/span> i <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;<\/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  }\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());      <span style=\"color: #0099FF; font-style: italic\">\/\/ (2)<\/span>\n  scheduler1.emplace(<span style=\"color: #FF6600\">1<\/span>, createTask(<span style=\"color: #CC3300\">&quot;  TaskB&quot;<\/span>).get_handle());    <span style=\"color: #0099FF; font-style: italic\">\/\/ (3)<\/span>\n  scheduler1.emplace(<span style=\"color: #FF6600\">2<\/span>, createTask(<span style=\"color: #CC3300\">&quot;    TaskC&quot;<\/span>).get_handle());  <span style=\"color: #0099FF; font-style: italic\">\/\/ (4)<\/span>\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<span style=\"color: #555555\">&lt;<\/span>decltype([](<span style=\"color: #007788; font-weight: bold\">int<\/span> a) { <span style=\"color: #006699; font-weight: bold\">return<\/span> a <span style=\"color: #555555\">-<\/span> <span style=\"color: #FF6600\">1<\/span>; })<span style=\"color: #555555\">&gt;<\/span> scheduler2;        \n\n  scheduler2.emplace(<span style=\"color: #FF6600\">0<\/span>, createTask(<span style=\"color: #CC3300\">&quot;TaskA&quot;<\/span>).get_handle());     <span style=\"color: #0099FF; font-style: italic\">\/\/ (5)<\/span>\n  scheduler2.emplace(<span style=\"color: #FF6600\">1<\/span>, createTask(<span style=\"color: #CC3300\">&quot;  TaskB&quot;<\/span>).get_handle());   <span style=\"color: #0099FF; font-style: italic\">\/\/ (6)<\/span>\n  scheduler2.emplace(<span style=\"color: #FF6600\">2<\/span>, createTask(<span style=\"color: #CC3300\">&quot;    TaskC&quot;<\/span>).get_handle()); <span style=\"color: #0099FF; font-style: italic\">\/\/ (7)<\/span>\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\n\n\n<p>The coroutine <code>createTask<\/code> takes its string by const lvalue reference (1), but its arguments <code>\"TaskA\" - \"TaskC\"<\/code>  are rvalues (lines 2 &#8211; 7).  Using the reference to the temporaries is undefined behavior. The additional schedulers <code>priority_SchedulerSimplified<\/code> and <code>priority_queueSchedulerComparator<\/code> in the posts &#8220;<a href=\"https:\/\/www.modernescpp.com\/index.php\/a-priority-scheduler-for-coroutines\/\" data-type=\"link\" data-id=\"https:\/\/www.modernescpp.com\/index.php\/a-priority-scheduler-for-coroutines\/\">A Priority Scheduler for Coroutines<\/a>&#8221; and  &#8220;<a href=\"https:\/\/www.modernescpp.com\/index.php\/an-advanced-priority-scheduler-for-coroutines\/\" data-type=\"link\" data-id=\"https:\/\/www.modernescpp.com\/index.php\/an-advanced-priority-scheduler-for-coroutines\/\">An Advanced Priority Scheduler for Coroutines<\/a>&#8221; suffer the same issue.<\/p>\n\n\n\n<p>Fixing the issue is straightforward. Either the coroutine <code>createTask <\/code>takes its argument by value (<code>Task createTask(std::string name<\/code>)) or its arguments become lvalues. Here is the second approach in lines (1) &#8211; (3):<\/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_queueSchedulerPriority.cpp<\/span>\n\n<span style=\"color: #009999\">#include &lt;concepts&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;coroutine&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;functional&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\">using<\/span> job <span style=\"color: #555555\">=<\/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;<\/span>;\n\n<span style=\"color: #006699; font-weight: bold\">template<\/span> <span style=\"color: #555555\">&lt;<\/span><span style=\"color: #006699; font-weight: bold\">typename<\/span> Updater <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>identity,                         \n          <span style=\"color: #006699; font-weight: bold\">typename<\/span> Comperator <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>ranges<span style=\"color: #555555\">::<\/span>less<span style=\"color: #555555\">&gt;<\/span>                   \nrequires std<span style=\"color: #555555\">::<\/span>invocable<span style=\"color: #555555\">&lt;<\/span>decltype(Updater()), <span style=\"color: #007788; font-weight: bold\">int<\/span><span style=\"color: #555555\">&gt;<\/span> <span style=\"color: #555555\">&amp;&amp;<\/span>                \n         std<span style=\"color: #555555\">::<\/span>predicate<span style=\"color: #555555\">&lt;<\/span>decltype(Comperator()), job, job<span style=\"color: #555555\">&gt;<\/span>             \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>job, std<span style=\"color: #555555\">::<\/span>vector<span style=\"color: #555555\">&lt;<\/span>job<span style=\"color: #555555\">&gt;<\/span>, Comperator<span style=\"color: #555555\">&gt;<\/span> _prioTasks;\n\n  <span style=\"color: #9999FF\">public:<\/span> \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      Updater upd <span style=\"color: #555555\">=<\/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(upd(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  <span style=\"color: #006699; font-weight: bold\">for<\/span> (<span style=\"color: #007788; font-weight: bold\">int<\/span> i <span style=\"color: #555555\">=<\/span> <span style=\"color: #FF6600\">0<\/span>; i <span style=\"color: #555555\">&lt;=<\/span> <span style=\"color: #FF6600\">3<\/span>; <span style=\"color: #555555\">++<\/span>i ) { \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 &quot;<\/span> <span style=\"color: #555555\">&lt;&lt;<\/span> i <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;<\/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  }\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  std<span style=\"color: #555555\">::<\/span>string taskA <span style=\"color: #555555\">=<\/span> <span style=\"color: #CC3300\">&quot;TaskA&quot;<\/span>;                    <span style=\"color: #0099FF; font-style: italic\">\/\/ (1)<\/span>\n  std<span style=\"color: #555555\">::<\/span>string taskB <span style=\"color: #555555\">=<\/span> <span style=\"color: #CC3300\">&quot;  TaskB&quot;<\/span>;                  <span style=\"color: #0099FF; font-style: italic\">\/\/ (2)<\/span>\n  std<span style=\"color: #555555\">::<\/span>string taskC <span style=\"color: #555555\">=<\/span> <span style=\"color: #CC3300\">&quot;    TaskC&quot;<\/span>;                <span style=\"color: #0099FF; font-style: italic\">\/\/ (3)<\/span>\n\n  Scheduler scheduler1;                                          \n\n  scheduler1.emplace(<span style=\"color: #FF6600\">0<\/span>, createTask(taskA).get_handle());\n  scheduler1.emplace(<span style=\"color: #FF6600\">1<\/span>, createTask(taskB).get_handle());\n  scheduler1.emplace(<span style=\"color: #FF6600\">2<\/span>, createTask(taskC).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<span style=\"color: #555555\">&lt;<\/span>decltype([](<span style=\"color: #007788; font-weight: bold\">int<\/span> a) { <span style=\"color: #006699; font-weight: bold\">return<\/span> a <span style=\"color: #555555\">-<\/span> <span style=\"color: #FF6600\">1<\/span>; })<span style=\"color: #555555\">&gt;<\/span> scheduler2;        \n\n  scheduler2.emplace(<span style=\"color: #FF6600\">0<\/span>, createTask(taskA).get_handle());\n  scheduler2.emplace(<span style=\"color: #FF6600\">1<\/span>, createTask(taskB).get_handle());\n  scheduler2.emplace(<span style=\"color: #FF6600\">2<\/span>, createTask(taskC).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\n\n<h2 class=\"wp-block-heading\">What&#8217;s Next? <\/h2>\n\n\n\n<p>Coroutines provide an intuitive way of writing asynchronous code. My next post will be a guest post from Ljubic Damir, presenting a single producer \u2013 single consumer workflow based on coroutines.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my last two posts, I presented priority schedulers for coroutines. The schedulers had a bug. First of all, here is the erroneous scheduler. \/\/ priority_queueSchedulerPriority.cpp #include &lt;concepts&gt; #include &lt;coroutine&gt; #include &lt;functional&gt; #include &lt;iostream&gt; #include &lt;queue&gt; #include &lt;utility&gt; struct Task { struct promise_type { std::suspend_always initial_suspend() noexcept { return {}; } std::suspend_always final_suspend() noexcept { [&hellip;]<\/p>\n","protected":false},"author":21,"featured_media":8780,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[445],"class_list":["post-8779","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\/8779","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=8779"}],"version-history":[{"count":12,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8779\/revisions"}],"predecessor-version":[{"id":8794,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8779\/revisions\/8794"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/8780"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=8779"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=8779"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=8779"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}