{"id":8669,"date":"2023-12-04T21:24:22","date_gmt":"2023-12-04T21:24:22","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=8669"},"modified":"2023-12-04T21:24:22","modified_gmt":"2023-12-04T21:24:22","slug":"an-advanced-priority-scheduler-for-coroutines","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/an-advanced-priority-scheduler-for-coroutines\/","title":{"rendered":"An Advanced Priority Scheduler for Coroutines"},"content":{"rendered":"\n<p>Today, I use the straightforward scheduler from the post &#8220;A Priority Scheduler for Coroutines&#8221; and improve its priority handling.<\/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 fourth post in my miniseries 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\n\n\n<li><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><\/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. Finally, my <code>std::priority_queue<\/code>-based scheduler in the last post supports the prioritization of tasks.<\/p>\n\n\n\n<p>In this post, I will improve the last scheduler in two ways. First, let me play with the comparison function of the <code>std::priority_queue.<\/code><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Comparator<\/h2>\n\n\n\n<p>The priority queue has its greatest element always at the top. <code>std::priority_queue<\/code> uses by default the comparison operator <code>std::less<\/code>. The following scheduler has the comparator as template parameter.<\/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_queueSchedulerComparator.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>;              <span style=\"color: #0099FF; font-style: italic\">\/\/ (1)<\/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> Comparator <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>ranges<span style=\"color: #555555\">::<\/span>less<span style=\"color: #555555\">&gt;<\/span>                <span style=\"color: #0099FF; font-style: italic\">\/\/ (2)<\/span>\nrequires std<span style=\"color: #555555\">::<\/span>predicate<span style=\"color: #555555\">&lt;<\/span>decltype(Comparator()), job, job<span style=\"color: #555555\">&gt;<\/span>         <span style=\"color: #0099FF; font-style: italic\">\/\/ (3)<\/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>, Comparator<span style=\"color: #555555\">&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));            <span style=\"color: #0099FF; font-style: italic\">\/\/ (6)<\/span>\n        }\n        <span style=\"color: #006699; font-weight: bold\">else<\/span> {\n          task.destroy();\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;                                              <span style=\"color: #0099FF; font-style: italic\">\/\/ (4)<\/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\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>std<span style=\"color: #555555\">::<\/span>ranges<span style=\"color: #555555\">::<\/span>greater<span style=\"color: #555555\">&gt;<\/span> scheduler2;                        <span style=\"color: #0099FF; font-style: italic\">\/\/ (5)<\/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\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>Please read the three previous posts if this scheduler is too overwhelming for you. First, I call the combination of a priority and a task a job (line 1). The scheduler takes a template parameter <code>Comparator <\/code>that is defaulted to <code>std::ranges::less<\/code> (line 2). Additionally, the concept <code>std:::predicate<\/code> checks in line (3),  if the predicate can be invoked with two jobs.  <\/p>\n\n\n\n<p><code>scheduler1<\/code> (line 5) starts with the highest prioritized job, but <code>scheduler2 <\/code>(line 6) with the lowest prioritized.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"585\" height=\"466\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueSchedulerComperator.png\" alt=\"\" class=\"wp-image-8679\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueSchedulerComperator.png 585w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/priority_queueSchedulerComperator-300x239.png 300w\" sizes=\"auto, (max-width: 585px) 100vw, 585px\" \/><\/figure>\n\n\n\n<p>In line 6, I push back the job onto the scheduler. Wouldn&#8217;t it be nice if I could update the priority of a pushed-back job? <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Updating the Priority<\/h2>\n\n\n\n<p>The following scheduler can additionally update the priority of a pushed-back job.<\/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<p>Only a few modifications on the scheduler in the program <code>priority_queueSchedulerComparator.cpp<\/code> are necessary to support updating priorities.<\/p>\n\n\n\n<p>First, the scheduler gets an additional template parameter <code>Updater<\/code>, (line 1) that is defaulted to <code>std::identity<\/code>. <code>Updater <\/code>must be invocable and take an <code>int<\/code>. Of course,<code> std::invocable<\/code> is a concept (line 2). The <code>Updater <\/code>is created in line (3) and applied in line (4). Additionally, the coroutine displays in line (5) which part of the task is executed.  <code>scheduler1<\/code> (line 6) performs its job, starting with the highest priority, but <code>scheduler2 <\/code>(line 7) decreases the priority of a pushed-back job by one. I use a lambda as invocable.<\/p>\n\n\n\n<p>The output of the program shows the different scheduling strategies.<\/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<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 &#8211; single consumer workflow based on coroutines.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today, I use the straightforward scheduler from the post &#8220;A Priority Scheduler for Coroutines&#8221; and improve its priority handling. This is the fourth post in my miniseries 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 [&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-8669","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\/8669","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=8669"}],"version-history":[{"count":25,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8669\/revisions"}],"predecessor-version":[{"id":8752,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8669\/revisions\/8752"}],"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=8669"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=8669"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=8669"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}