{"id":10359,"date":"2024-11-25T09:06:27","date_gmt":"2024-11-25T09:06:27","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=10359"},"modified":"2025-07-04T15:40:47","modified_gmt":"2025-07-04T15:40:47","slug":"stdexecution-asynchronous-algorithms","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/stdexecution-asynchronous-algorithms\/","title":{"rendered":"std::execution: Asynchronous Algorithms"},"content":{"rendered":"\n<p> <code>std::execution <\/code>supports many asynchronous algorithms for various workflows.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"711\" height=\"491\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/11\/Timeexecution.png\" alt=\"\" class=\"wp-image-10323\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/11\/Timeexecution.png 711w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/11\/Timeexecution-300x207.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/11\/Timeexecution-705x487.png 705w\" sizes=\"auto, (max-width: 711px) 100vw, 711px\" \/><\/figure>\n\n\n\n<p>Presenting proposal <a href=\"https:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2024\/p2300r10.html\">P2300R10<\/a> is not easy. First, it is very powerful, and second, it is very long. Therefore, I concentrate on specific aspects of the proposal.<\/p>\n\n\n\n<p>What are the priorities of this proposal?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Priorities<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Be composable and generic, allowing users to write code that can be used with many different types of execution resources.<\/li>\n\n\n\n<li>Encapsulate common asynchronous patterns in customizable and reusable algorithms, so users don\u2019t have to invent things themselves.<\/li>\n\n\n\n<li>Make it easy to be correct by construction.<\/li>\n\n\n\n<li>Support the diversity of execution resources and execution agents, because not all execution agents are created equal; some are less capable than others, but not less important.<\/li>\n\n\n\n<li>Allow everything to be customized by an execution resource, including transfer to other execution resources, but don\u2019t require that execution resources customize everything.<\/li>\n\n\n\n<li>Care about all reasonable use cases, domains and platforms.<\/li>\n\n\n\n<li>Errors must be propagated, but error handling must not present a burden.<\/li>\n\n\n\n<li>Support cancellation, which is not an error.<\/li>\n\n\n\n<li>Have clear and concise answers for where things execute.<\/li>\n\n\n\n<li>Be able to manage and terminate the lifetimes of objects asynchronously.<\/li>\n<\/ul>\n\n\n\n<p>The terms execution resource, execution agent, and scheduler are essential for the understanding of <code>std::execution<\/code>. Here are the first simplified definitions.<\/p>\n\n\n\n<p>An <strong>execution resource<\/strong> is a program resource entity that manages a set of execution agents. Examples of execution resources include the active thread, a thread pool, or an extra hardware accelerator.<\/p>\n\n\n\n<p>Each function invocation runs in an <strong>execution agent<\/strong>.<\/p>\n\n\n\n<p>A <strong>scheduler <\/strong>is an abstraction of an execution resource with a uniform, generic interface for scheduling work onto that resource. It is a factory for senders.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Hello World<\/h2>\n\n\n\n<p> Here&#8217;s once more the &#8220;Hello World&#8221; of <code>std::execution<\/code>. You can execute the program on <a href=\"https:\/\/godbolt.org\/z\/TPrajoxxT\">Compiler Explorer <\/a>this time, and my analysis will go deeper.<\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:100%\">\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\">\/\/ HelloWorldExecution.cpp<\/span>\n\n<span style=\"color: #009999\">#include &lt;exec\/static_thread_pool.hpp&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;stdexec\/execution.hpp&gt;<\/span>\n\n\n<span style=\"color: #007788; font-weight: bold\">int<\/span> <span style=\"color: #CC00FF\">main<\/span>() {\n  exec<span style=\"color: #555555\">::<\/span>static_thread_pool pool(<span style=\"color: #FF6600\">8<\/span>);\n  <span style=\"color: #006699; font-weight: bold\">auto<\/span> sch <span style=\"color: #555555\">=<\/span> pool.get_scheduler();\n\n  <span style=\"color: #006699; font-weight: bold\">auto<\/span> begin <span style=\"color: #555555\">=<\/span> stdexec<span style=\"color: #555555\">::<\/span>schedule(sch);\n  <span style=\"color: #006699; font-weight: bold\">auto<\/span> hi <span style=\"color: #555555\">=<\/span> stdexec<span style=\"color: #555555\">::<\/span>then(begin, [] {\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Hello world! Have an int.<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n    <span style=\"color: #006699; font-weight: bold\">return<\/span> <span style=\"color: #FF6600\">13<\/span>;\n  });\n  <span style=\"color: #006699; font-weight: bold\">auto<\/span> add_42 <span style=\"color: #555555\">=<\/span> stdexec<span style=\"color: #555555\">::<\/span>then(hi, [](<span style=\"color: #007788; font-weight: bold\">int<\/span> arg) { <span style=\"color: #006699; font-weight: bold\">return<\/span> arg <span style=\"color: #555555\">+<\/span> <span style=\"color: #FF6600\">42<\/span>; });\n\n  <span style=\"color: #006699; font-weight: bold\">auto<\/span> [i] <span style=\"color: #555555\">=<\/span> stdexec<span style=\"color: #555555\">::<\/span>sync_wait(add_42).value();\n\n  std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;i = &quot;<\/span> <span style=\"color: #555555\">&lt;&lt;<\/span> i <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n}\n<\/pre><\/div>\n<\/div>\n<\/div>\n\n\n\n<p>First, here&#8217;s the output of the program:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"285\" height=\"60\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/11\/HelloWorldExecution.png\" alt=\"\" class=\"wp-image-10367\"\/><\/figure>\n\n\n\n<p>The program begins by including the necessary headers: <code>&lt;exec\/static_thread_pool.hpp&gt;<\/code> for creating a thread pool, and <code>&lt;stdexec\/execution.hpp&gt;<\/code> for execution-related utilities.<\/p>\n\n\n\n<p>In the <code>main<\/code> function, a <code>static_thread_pool<\/code> <code>pool <\/code>is created with 8 threads. <\/p>\n\n\n\n<p>The <code>get_scheduler<\/code> member function of the thread pool is called to obtain a lightweight handle for the execution resource scheduler object named <code>sch<\/code>, which will be used to schedule senders on the thread pool. In this case, the execution resource is a thread pool, but it could also be the main thread, the GPU, or a task framework<\/p>\n\n\n\n<p>The program then creates a series of senders executed by executing agents. <\/p>\n\n\n\n<p>The first sender, <code>begin<\/code>, is created using the <code>stdexec::schedule<\/code> function, which schedules a sender on the specified scheduler <code>sch<\/code>. <code>stdexec::schedule<\/code> is a so-called sender factory. There are more sender factories. I use the namespace of the upcoming standard:<\/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%\">execution<span style=\"color: #555555\">::<\/span>schedule\nexecution<span style=\"color: #555555\">::<\/span>just\nexecution<span style=\"color: #555555\">::<\/span>just_error\nexecution<span style=\"color: #555555\">::<\/span>just_stopped\nexecution<span style=\"color: #555555\">::<\/span>read_env\n<\/pre><\/div>\n\n\n\n<p>The next sender, <code>hi<\/code>, uses the sender adaptor <code>stdexec::then<\/code>, which takes the <code>begin <\/code>sender and a lambda function. This lambda function prints &#8220;<code>Hello world! Have an int<\/code>.&#8221; to the console and returns the integer value 13. The third sender, <code>add_42<\/code>, is also created using the sender adaptor <code>stdexec::then<\/code>. The continuation takes the <code>hi <\/code>task and another lambda, which takes an integer argument <code>arg <\/code>and returns the result of adding 42 to it. Senders run asynchronously and are generally composable.<\/p>\n\n\n\n<p><code>std::execution<\/code> offers more sender adapters:<\/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%\">execution<span style=\"color: #555555\">::<\/span>continues_on\nexecution<span style=\"color: #555555\">::<\/span>then\nexecution<span style=\"color: #555555\">::<\/span>upon_<span style=\"color: #555555\">*<\/span>\nexecution<span style=\"color: #555555\">::<\/span>let_<span style=\"color: #555555\">*<\/span>\nexecution<span style=\"color: #555555\">::<\/span>starts_on\nexecution<span style=\"color: #555555\">::<\/span>into_variant\nexecution<span style=\"color: #555555\">::<\/span>stopped_as_optional\nexecution<span style=\"color: #555555\">::<\/span>stopped_as_error\nexecution<span style=\"color: #555555\">::<\/span>bulk\nexecution<span style=\"color: #555555\">::<\/span>split\nexecution<span style=\"color: #555555\">::<\/span>when_all\n<\/pre><\/div>\n\n\n\n<p>In contrast to the senders, runs the sender consumer synchronously. The <code>stdexec::sync_wait<\/code> call waits for the completion of the <code>add_42<\/code> sender. The <code>value<\/code> method is called on the result of<code> sync_wait <\/code>to obtain the value produced by the sender, which is unpacked into the variable <code>i<\/code>.<\/p>\n\n\n\n<p><code>this_thread::sync_wait<\/code> is the only sender consumer in the execution framework.<\/p>\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 analyze a more challenging algorithm.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>std::execution supports many asynchronous algorithms for various workflows. Presenting proposal P2300R10 is not easy. First, it is very powerful, and second, it is very long. Therefore, I concentrate on specific aspects of the proposal. What are the priorities of this proposal? Priorities The terms execution resource, execution agent, and scheduler are essential for the understanding [&hellip;]<\/p>\n","protected":false},"author":21,"featured_media":10323,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[559],"tags":[561],"class_list":["post-10359","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c26-blog","tag-execution"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10359","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=10359"}],"version-history":[{"count":17,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10359\/revisions"}],"predecessor-version":[{"id":10385,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10359\/revisions\/10385"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/10323"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=10359"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=10359"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=10359"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}