{"id":5870,"date":"2020-03-27T08:10:41","date_gmt":"2020-03-27T08:10:41","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-20-coroutines-more-details\/"},"modified":"2023-09-28T07:45:21","modified_gmt":"2023-09-28T07:45:21","slug":"c-20-coroutines-more-details","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-20-coroutines-more-details\/","title":{"rendered":"C++20: More Details to Coroutines"},"content":{"rendered":"<p>After I gave you in my last post (<a href=\"https:\/\/bit.ly\/3dl4VGE\">C++20: Coroutines &#8211; A First Overview<\/a>) my first impression of coroutines, I want to provide more details today.\u00a0Once more, we get in C++20 not coroutines but a framework for building coroutines.<\/p>\n<p><!--more--><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8406 size-full\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Coroutines.png\" alt=\"\" width=\"1068\" height=\"383\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Coroutines.png 1068w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Coroutines-300x108.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Coroutines-1030x369.png 1030w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Coroutines-768x275.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Coroutines-705x253.png 705w\" sizes=\"auto, (max-width: 1068px) 100vw, 1068px\" \/><\/p>\n<p>My job in this and further posts is to explain the framework for building coroutines. Ultimately, you can create your own or use an existing implementation of coroutines such as the excellent one\u00a0<a href=\"https:\/\/github.com\/lewissbaker\/cppcoro\">cppcoro<\/a>\u00a0from Lewis Baker.<\/p>\n<p>Today&#8217;s post is in-between: This post is not an overview but also not an in-depth dive into the coroutines framework that follows in the next posts.<\/p>\n<p>The first question you may have is: When should I use coroutines?<\/p>\n<h2>Typical Use-Cases<\/h2>\n<p>Coroutines are the usual way to write <a href=\"https:\/\/en.wikipedia.org\/wiki\/Event-driven_programming\">event-driven applications<\/a>. The event-driven application can\u00a0be simulations, games, servers, user interfaces, or algorithms. For example, I wrote a a few years ago a defibrillator simulator in Python. This simulator helped us, in particular, to make clinical usability studies. A defibrillator is an event-driven application, and I implemented it, consequentially, based on the event-driven Python framework <a href=\"https:\/\/twistedmatrix.com\/trac\/\">twisted<\/a>.<\/p>\n<p>Coroutines are also typically used for\u00a0cooperative multitasking. The key to cooperative multitasking is that each task takes as much time\u00a0as it needs. Cooperative <a href=\"https:\/\/en.wikipedia.org\/wiki\/Computer_multitasking\">multitasking<\/a> stands in contrast to preemptive multitasking, for which a scheduler decides how long each task gets the CPU. Cooperative multitasking often makes concurrency easier because a concurrent job can not be interrupted in a critical region. If you are still puzzled by the terms cooperative and preemptive, I found an excellent overview and read here:\u00a0<a href=\"https:\/\/medium.com\/traveloka-engineering\/cooperative-vs-preemptive-a-quest-to-maximize-concurrency-power-3b10c5a920fe\">Cooperative vs. Preemptive: a quest to maximize concurrency power<\/a><\/p>\n<p><span style=\"color: inherit; font-size: 35px;\">Underlying Ideas<\/span><\/p>\n<p>Coroutines in C++20 are asymmetric, first-class, and stackless.<\/p>\n<ul>\n<li>The workflow of an <strong>asymmetric<\/strong> coroutine goes back to the caller.<\/li>\n<li><strong>First-class<\/strong> coroutines behave like data. Behaving like data means using them as an argument to return value from a function or store them in a variable.<\/li>\n<li>A <strong>stackless<\/strong> coroutine enables it to suspend and resume the top-level coroutine. The execution of\u00a0the coroutine and the yielding from the coroutine comes back to the caller.\u00a0In contrast, a stackful coroutine reserves a default stack for 1MB on Windows, and 2MB<br \/>\non Linux.<\/li>\n<\/ul>\n<h2>Design Goals<\/h2>\n<p>Gor Nishanov, how was responsible for the standardization of coroutines in C++,\u00a0 described the design goals of coroutines.\u00a0Coroutines should<\/p>\n<ul>\n<li>be highly scalable (to billions of concurrent coroutines).<\/li>\n<li>have highly efficient resume and suspend operations comparable in cost to the overhead of a\u00a0function.<\/li>\n<li>seamlessly interact with existing facilities with no overhead.<\/li>\n<li>have open-ended coroutine machinery allowing library designers to develop coroutine libraries.<\/li>\n<li>exposing various high-level semantics such as generators, goroutines, tasks and more.<\/li>\n<li>usable in environments where exceptions are forbidden or not available.<\/li>\n<\/ul>\n<h2>Becoming a Coroutine<\/h2>\n<p>A function that uses the keywords <code>co_return<\/code>, <code>co_yield,<\/code> or <code>co_await<\/code> becomes a coroutine implicitly.<\/p>\n<ul>\n<li><span style=\"font-family: 'courier new', courier;\"><strong>co_return<\/strong>: <\/span>a coroutine uses <span style=\"font-family: 'courier new', courier;\">co_return<\/span> as return statement.<\/li>\n<li><span style=\"font-family: 'courier new', courier;\"><strong>co_yield<\/strong>:\u00a0<\/span>thanks to <span style=\"font-family: 'courier new', courier;\">co_yield<\/span>, you can implement a generator that generates an infinite data stream\u00a0from which you can successively query values. The return type of the function call\u00a0<span style=\"font-family: 'courier new', courier;\">generatorForNumbers(int begin, int inc= 1)<\/span>, such as in the last post (<a href=\"https:\/\/bit.ly\/3dl4VGE\">C++20: Coroutines &#8211; A First Overview<\/a>) is a generator. A generator internally holds\u00a0a special promise <span style=\"font-family: 'courier new', courier;\">pro<\/span> so that a call <span style=\"font-family: 'courier new', courier;\">co_yield i<\/span> is equivalent to a call <span style=\"font-family: 'courier new', courier;\">co_await pro.yield_value(i)<\/span>. Immediately after the call, the coroutine is paused.<\/li>\n<li><strong><span style=\"font-family: 'courier new', courier;\">co_await:<\/span><\/strong><span style=\"font-family: 'courier new', courier;\">co_await<\/span> eventually causes the execution of the coroutine to be suspended or resumed.\u00a0The expression <span style=\"font-family: 'courier new', courier;\">exp<\/span> in <span style=\"font-family: 'courier new', courier;\">co_await<\/span> exp has to be a so-called awaitable expression. <span style=\"font-family: 'courier new', courier;\">exp<\/span> has to implement\u00a0a specific interface. This interface consists of three functions <span style=\"font-family: 'courier new', courier;\">await_ready<\/span>, <span style=\"font-family: 'courier new', courier;\">await_suspend<\/span>,\u00a0and <span style=\"font-family: 'courier new', courier;\">await_resume<\/span>.<\/li>\n<\/ul>\n<h3>Two Awaitables<\/h3>\n<p>The C++20 standard already defines two awaitables as basic-building blocks: <span style=\"font-family: 'courier new', courier;\">std::suspend_always<\/span>, and <span style=\"font-family: 'courier new', courier;\">std::suspend_never<\/span>.<\/p>\n<ul>\n<li><span style=\"font-family: 'courier new', courier;\">std::suspend_always<\/span><\/li>\n<\/ul>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<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>\n<\/div>\n<p>The awaitable <span style=\"font-family: 'courier new', courier;\">std::suspend_always<\/span> suspends always because <span style=\"font-family: 'courier new', courier;\">await_ready<\/span> returns <span style=\"font-family: 'courier new', courier;\">false<\/span>. The opposite holds for <span style=\"font-family: 'courier new', courier;\">std::suspend_never.<\/span><\/p>\n<ul>\n<li><span style=\"font-family: 'courier new', courier;\">std::suspend_never<\/span><\/li>\n<\/ul>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #006699; font-weight: bold;\">struct<\/span> suspend_never {<\/pre>\n<\/div>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">    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;\">true<\/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>\n<\/div>\n<p>I hope a small example helps to make the theory easier to digest. A server is the hello world example for coroutines.<\/p>\n<h3>A Blocking and a Waiting Server<\/h3>\n<p>A server is an event-driven application. It typically waits in an event loop for an indication event of a client.<\/p>\n<p>The following code snippet shows the structure of a straightforward server.<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">Acceptor acceptor{<span style=\"color: #ff6600;\">443<\/span>};               <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\n \n<span style=\"color: #006699; font-weight: bold;\">while<\/span> (<span style=\"color: #336666;\">true<\/span>){\n    Socket socket<span style=\"color: #555555;\">=<\/span> acceptor.accept(); <span style=\"color: #0099ff; font-style: italic;\">\/\/ blocking (2)<\/span>\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> request<span style=\"color: #555555;\">=<\/span> socket.read();      <span style=\"color: #0099ff; font-style: italic;\">\/\/ blocking (3)<\/span>\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> response<span style=\"color: #555555;\">=<\/span> handleRequest(request);\n    socket.write(response);           <span style=\"color: #0099ff; font-style: italic;\">\/\/ blocking (4)<\/span>\n}\n<\/pre>\n<\/div>\n<p>The sequential server answers each request in the same thread. It\u00a0listens on port 443 (line 1), accepts its connections (line 2), reads the incoming data from the\u00a0client (line 3), and writes its answer to the client (line 4). The calls in lines 2, 3, and 4 are blocking.<\/p>\n<p>Thanks to <span style=\"font-family: 'courier new', courier;\">co_await,\u00a0<\/span>the blocking calls can now be suspended and resumed. The resources-consuming blocking server becomes a resource-sparing waiting server.<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">Acceptor acceptor{<span style=\"color: #ff6600;\">443<\/span>};\n\n<span style=\"color: #006699; font-weight: bold;\">while<\/span> (<span style=\"color: #336666;\">true<\/span>){\n    Socket socket<span style=\"color: #555555;\">=<\/span> co_await acceptor.accept();\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> request<span style=\"color: #555555;\">=<\/span> co_await socket.read();\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> response<span style=\"color: #555555;\">=<\/span> handleRequest(request);\n    co_await socket.write(response);\n}\n<\/pre>\n<\/div>\n<p>You may guess. The crucial part of understanding this coroutine is the awaitable expressions <span style=\"font-family: 'courier new', courier;\">expr<\/span> in the\u00a0<span style=\"font-family: 'courier new', courier;\">co_await expr\u00a0<\/span>calls. These expressions have to implement the functions <span style=\"font-family: 'courier new', courier;\">await_ready<\/span>, <span style=\"font-family: 'courier new', courier;\">await_suspend<\/span>, and <span style=\"font-family: 'courier new', courier;\">await_resume<\/span>.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>The framework for writing a coroutine consists of more than 20 functions that you partially have to implement and partially could overwrite. My <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-20-an-infinite-data-stream-with-coroutines\">next post <\/a>dives deeper into this framework.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After I gave you in my last post (C++20: Coroutines &#8211; A First Overview) my first impression of coroutines, I want to provide more details today.\u00a0Once more, we get in C++20 not coroutines but a framework for building coroutines.<\/p>\n","protected":false},"author":21,"featured_media":8406,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[445],"class_list":["post-5870","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\/5870","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=5870"}],"version-history":[{"count":2,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5870\/revisions"}],"predecessor-version":[{"id":8425,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5870\/revisions\/8425"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/8406"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5870"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5870"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5870"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}