{"id":8605,"date":"2023-11-13T11:11:14","date_gmt":"2023-11-13T11:11:14","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=8605"},"modified":"2023-11-22T18:20:56","modified_gmt":"2023-11-22T18:20:56","slug":"a-concise-introduction-to-coroutines-by-dian-lun-li","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/a-concise-introduction-to-coroutines-by-dian-lun-li\/","title":{"rendered":"A Concise Introduction to Coroutines by Dian-Lun Lin"},"content":{"rendered":"\n<p>Today, I will start a miniseries about a scheduler for tasks. The starting point of this miniseries is a straightforward scheduler by Dian-Lun Lin that becomes increasingly sophisticated.<\/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>I have already written around 15 posts about <a href=\"https:\/\/www.modernescpp.com\/index.php\/tag\/coroutines\/\" data-type=\"link\" data-id=\"https:\/\/www.modernescpp.com\/index.php\/tag\/coroutines\/\">coroutines<\/a>. They explain the theory about coroutines and apply this theory in various ways. However, I still fight for an intuitive introduction to a non-trivial coroutine use case. I was, therefore, pretty happy to watch  Dian-Lun Lin CppCon 2022 talk: &#8220;<a href=\"https:\/\/www.youtube.com\/watch?v=kIPzED3VD3w\">An Introduction to C++ Coroutines through a Thread Scheduling Demonstration<\/a>&#8220;. <\/p>\n\n\n\n<p>Today, I&#8217;m happy to present a guest post by Dian-Lun Lin. He will intuitively introduce coroutines to implement a straightforward scheduler that dispatches tasks. I will use this scheduler as a starting point for further experiments.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">An Introduction to C++ Coroutines<\/h2>\n\n\n\n<p>A coroutine is a function that can suspend itself and be resumed by the caller. Unlike regular functions, which execute sequentially from start to finish, coroutines allow for controlled suspension and resumption of execution. This enables us to write code that looks synchronous but can efficiently handle asynchronous operations without blocking the calling thread.<br>Implementing a C++ coroutine can be a bit challenging due to its versatility. In C++ coroutines, you can fine-tune how a coroutine behaves in numerous ways. For example, you can decide whether a coroutine should be suspended when it starts or finishes, and you can precisely adjust when and where these suspensions occur within the coroutine. To illustrate, let&#8217;s begin with a straightforward example:<\/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\">\/\/ simpleCoroutine.cpp<\/span>\n\n<span style=\"color: #009999\">#include &lt;coroutine&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;iostream&gt;<\/span>\n\n<span style=\"color: #006699; font-weight: bold\">struct<\/span> MyCoroutine {                             <span style=\"color: #0099FF; font-style: italic\">\/\/ (1)<\/span>\n    <span style=\"color: #006699; font-weight: bold\">struct<\/span> promise_type {\n        MyCoroutine 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        std<span style=\"color: #555555\">::<\/span>suspend_always initial_suspend() {\n            <span style=\"color: #006699; font-weight: bold\">return<\/span> {};\n        }\n        std<span style=\"color: #555555\">::<\/span>suspend_always final_suspend() noexcept {\n            <span style=\"color: #006699; font-weight: bold\">return<\/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    MyCoroutine(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: #007788; font-weight: bold\">void<\/span> resume() { \n        handle.resume(); \n    }\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> destroy() { \n        handle.destroy(); \n    }\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\nMyCoroutine <span style=\"color: #CC00FF\">simpleCoroutine<\/span>() {                      <span style=\"color: #0099FF; font-style: italic\">\/\/ (2)<\/span>\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Start coroutine<\/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> <span style=\"color: #CC3300\">&quot;Resume coroutine<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n}\n\n<span style=\"color: #007788; font-weight: bold\">int<\/span> <span style=\"color: #CC00FF\">main<\/span>() {\n    MyCoroutine coro <span style=\"color: #555555\">=<\/span> simpleCoroutine();\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Coroutine is not executed yet<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n    coro.resume();\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Suspend coroutine<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n    coro.resume();\n    coro.destroy();\n    <span style=\"color: #006699; font-weight: bold\">return<\/span> <span style=\"color: #FF6600\">0<\/span>;\n}\n<\/pre><\/div>\n\n\n\n<p><br>This example code demonstrates the basic usage of C++ coroutines and provides an example of a custom coroutine. To implement a C++ coroutine, you must understand four essential components: <em>Coroutine<\/em>, <em>Promise type<\/em>, <em>Awaitable<\/em>, and <em>Coroutine handle<\/em>. I will explain each component through the example code in the following sections.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Coroutine<\/h3>\n\n\n\n<p>In C++, coroutines are implemented through the <code>co_return<\/code>, <code>co_await<\/code>, and <code>co_yield <\/code>keywords. These keywords allow developers to express asynchronous behavior in a structured and intuitive way. In the example coroutine, <code>simpleCoroutine<\/code>, I call <code>co_await std::suspend always{}<\/code> to suspend the coroutine. The <code>std::suspend_always <\/code>is a C++ standard provided awaitable that always suspends the coroutine.<br><\/p>\n\n\n\n<p>When you call the function <code>simpleCoroutine<\/code>, it doesn\u2019t execute the coroutine immediately. Instead, it returns a coroutine object that defines <code>promise type<\/code>. Line (2) defines the function <code>simpleCoroutine <\/code>that returns a <code>MyCoroutine <\/code>object. In line (1), I define the <code>MyCoroutine <\/code>class and the promise type. You might wonder why calling a coroutine function doesn\u2019t immediately execute it. Again, this is because C++ Coroutine is designed to be flexible. C++ Coroutine allows you to decide when and how a coroutine should begin and end. This is defined in the <code>promise_type<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Promise Type<\/h3>\n\n\n\n<p>A <code>promise_type <\/code>controls a coroutine\u2019s behavior. Here are the key responsibilities of a <code>promise_type<\/code>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Creating the Coroutine Object: The <code>get_return_object <\/code>function creates an instance of the coroutine and returns it to the caller.<\/li>\n\n\n\n<li>Controlling Suspension: The <code>initial_suspend <\/code>and <code>final_suspend <\/code>functions determine whether the coroutine should be suspended or resumed at the beginning and the end. They return awaitables that dictate how the coroutine behaves.<\/li>\n\n\n\n<li>Handling Return Values: The <code>return_value <\/code>function sets the return value of the coroutine when it completes. It enables the coroutine to produce a result that the caller can retrieve. In the example code, I use <code>return_void<\/code>, indicating this coroutine does not have the return value.<\/li>\n\n\n\n<li>Handling Exceptions: The <code>unhandled_exception <\/code>function is invoked when an unhandled exception occurs within the coroutine. It provides a mechanism to handle exceptions gracefully.<\/li>\n<\/ul>\n\n\n\n<p>But where is the <code>promise_type <\/code>used? I do not see the word \u201dpromise\u201d in the example code. Actually, when you write your coroutine, the compiler sees your code slightly differently. The compiler\u2019s simplified view of <code>simpleCoroutine <\/code>is the following:<\/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%\">MyCoroutine <span style=\"color: #CC00FF\">simpleCoroutine<\/span>() {\n    MyCoroutine<span style=\"color: #555555\">::<\/span>promise_type p();\n    MyCoroutine coro_obj <span style=\"color: #555555\">=<\/span> p.get_return_object();\n\n    try {\n      co_await p.inital_suspend();\n      std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Start coroutine<\/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> <span style=\"color: #CC3300\">&quot;Resume coroutine<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n    } <span style=\"color: #006699; font-weight: bold\">catch<\/span>(...) {\n      p.unhandled_exception();\n    }\n    co_await p.final_suspend();\n}\n<\/pre><\/div>\n\n\n\n<p>That\u2019s why you need to define <code>promise_type <\/code>in the <code>MyCoroutine <\/code>class. When <code>simpleCoroutine <\/code>is called, the compiler creates a <code>promise_type <\/code>and calls <code>get_return_object<\/code>() to create the <code>MyCoroutine <\/code>object. Before the coroutine body, the compiler calls <code>initial_suspend <\/code>to determine whether to suspend at the beginning. Finally, it calls <code>final_suspend <\/code>to determine whether to suspend at the end. You will get compilation errors if you don\u2019t define <code>promise_type <\/code>and its corresponding functions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Awaitable<\/h3>\n\n\n\n<p>An awaitable controls a suspension point behavior. Three functions need to be defined for an awaitable:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>await_ready<\/code><\/strong>: This function determines whether the coroutine can proceed without suspension. It should return <code>true<\/code> if the operation is ready to continue immediately, or <code>false <\/code>if suspension is required. This method is an optimization that allows you to avoid the cost of suspension in cases where it is known that the operation will be completed synchronously.<\/li>\n\n\n\n<li><strong><code>await_suspend<\/code><\/strong>: This function provides fine-grained control over a suspension point behavior. It passes the current coroutine handle for users to resume the coroutine later or destroy the coroutine. There are three return types for this function:\n<ul class=\"wp-block-list\">\n<li><code><strong>void<\/strong><\/code>: We suspend the coroutine. The control is immediately returned to the caller of the current coroutine.<\/li>\n\n\n\n<li><code><strong>bool<\/strong><\/code>: If <code>true<\/code>, we suspend the current coroutine and return control to the caller; If <code>false<\/code>, we resume the current coroutine.<\/li>\n\n\n\n<li><code><strong>coroutine_handle<\/strong><\/code>: We suspend the current coroutine and resume that returned coroutine handle. This is also called asymmetric transfer.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><code><strong>await_resume<\/strong><\/code>: This function specifies what value should be returned to the coroutine when the awaited operation is complete. It resumes the coroutine\u2019s execution, passing the awaited result. If no result is expected or needed, this function can be empty and return <code>void<\/code>.<\/li>\n<\/ul>\n\n\n\n<p>But where are these functions used? Again, let\u2019s look into the compiler\u2019s view. When you call<code> co_await std:suspend_always{}<\/code>, the compiler will transform it into the following 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: #006699; font-weight: bold\">auto<\/span><span style=\"color: #555555\">&amp;&amp;<\/span> awaiter <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>suspend_always{};\n  <span style=\"color: #006699; font-weight: bold\">if<\/span>(<span style=\"color: #555555\">!<\/span>awaiter.await_ready()) {\n    awaiter.await_suspend(std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;&gt;<\/span>...);\n    <span style=\"color: #0099FF; font-style: italic\">\/\/&lt;suspend\/resume&gt;<\/span>\n  }\nawaiter.await_resume();\n<\/pre><\/div>\n\n\n\n<p>That\u2019s why you need to define all these functions. The <code>std::suspend_always<\/code> is a C++ built-in awaitable that defines the functions as follows:<\/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\">struct<\/span> suspend_always {\n    constexpr <span style=\"color: #007788; font-weight: bold\">bool<\/span> await_ready() <span style=\"color: #006699; font-weight: bold\">const<\/span> noexcept { <span style=\"color: #006699; font-weight: bold\">return<\/span> <span style=\"color: #336666\">false<\/span>; }\n    constexpr <span style=\"color: #007788; font-weight: bold\">void<\/span> await_suspend(coroutine_handle<span style=\"color: #555555\">&lt;&gt;<\/span>) <span style=\"color: #006699; font-weight: bold\">const<\/span> noexcept {}\n    constexpr <span style=\"color: #007788; font-weight: bold\">void<\/span> await_resume() <span style=\"color: #006699; font-weight: bold\">const<\/span> noexcept {}\n};\n<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Coroutine Handle<\/h3>\n\n\n\n<p>Coroutine handles are used to manage the state and lifecycle of a coroutine. They provide a way to access, resume, and destroy coroutines explicitly. In the example, I call <code>handle.resume() <\/code>to resume the coroutine and call <code>handle.destroy()<\/code> to destroy the coroutine.<\/p>\n\n\n\n<p><br>After executing the program, the results are the following:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"434\" height=\"234\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/simpleCoroutine.png\" alt=\"\" class=\"wp-image-8624\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/simpleCoroutine.png 434w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/simpleCoroutine-300x162.png 300w\" sizes=\"auto, (max-width: 434px) 100vw, 434px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">What&#8217;s Next?<\/h2>\n\n\n\n<p>As promised, this post from Dian-Lun Lin was a concise introduction to coroutines. In the next post, Dian-Lun applies the theory to implement a single-threaded scheduler for C++ coroutines.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today, I will start a miniseries about a scheduler for tasks. The starting point of this miniseries is a straightforward scheduler by Dian-Lun Lin that becomes increasingly sophisticated. I have already written around 15 posts about coroutines. They explain the theory about coroutines and apply this theory in various ways. However, I still fight for [&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-8605","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\/8605","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=8605"}],"version-history":[{"count":35,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8605\/revisions"}],"predecessor-version":[{"id":8741,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8605\/revisions\/8741"}],"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=8605"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=8605"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=8605"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}