{"id":5882,"date":"2020-04-16T14:38:24","date_gmt":"2020-04-16T14:38:24","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-20-coroutines-with-cppcoro\/"},"modified":"2023-09-28T07:43:19","modified_gmt":"2023-09-28T07:43:19","slug":"c-20-coroutines-with-cppcoro","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-20-coroutines-with-cppcoro\/","title":{"rendered":"C++20: Coroutines with cppcoro"},"content":{"rendered":"<p>The cppcoro library from Lewis Baker gives you what C++20 doesn&#8217;t: a library of C++ coroutine abstractions based on the coroutines TS.<\/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>Arguably, the two last posts, &#8220;<a href=\"https:\/\/bit.ly\/InfiniteDataStream\">C++20: An Infinite Data Stream with Coroutines<\/a>&#8221; and &#8220;<a href=\"https:\/\/bit.ly\/ThreadSynchronizationCoroutines\">C++20: Thread Synchronization with Coroutines<\/a>&#8221; were challenging to comprehend. The following posts to coroutines are easier to digest. I present examples of existing coroutines in <a href=\"https:\/\/github.com\/lewissbaker\/cppcoro\">cppcoro<\/a>.<\/p>\n<p>I speak from the coroutines and the coroutines framework to make my argument easier.<\/p>\n<h2>cppcoro<\/h2>\n<p>The coroutine TS is the base of the cppcoro library from Lewis Baker. TS stands for technical specifications and is the preliminary version of the coroutines framework we get with C++20. Lewis will port the cppcoro library from the coroutines TS framework to the coroutines framework we get with C++20.<\/p>\n<p>Porting the library is very important because <strong>we get not coroutines with C++20; we get a coroutines framework.<\/strong> This difference means you are on your own if you want to use coroutines in C++20. You have to create your coroutines based on the C++20 coroutines framework. Presumably, we get concrete coroutines with C++23. Honestly, I see this as extremely critical because implementing coroutines is quite challenging and error-prone. This gap is precisely the gap that cppcoro fills. It provides abstractions for coroutine types, awaitable types, functions, cancellation, schedulers, networking, and metafunctions, and defines a few concepts.<\/p>\n<h3>Using cppcoro<\/h3>\n<p>Currently, cppcoro is based on the coroutines TS frameworks and can be used on Windows (Visual Studio 2017) or Linux (Clang 5.0\/6.0 and libc++). For your experiments, I used the following command line for all of the examples:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5878\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroBuild.png\" alt=\"cppcoroBuild\" width=\"650\" height=\"82\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroBuild.png 1279w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroBuild-300x38.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroBuild-1024x130.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroBuild-768x97.png 768w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<ul>\n<li><span style=\"font-family: courier new, courier;\">-std=c++17<\/span>: support for C++17<\/li>\n<li><span style=\"font-family: courier new, courier;\">-fcoroutines-ts<\/span>: support for C++ coroutines TS<\/li>\n<li><span style=\"font-family: courier new, courier;\">-Iinclude<\/span>: cppcoro headers<\/li>\n<li><span style=\"font-family: courier new, courier;\">-stdlib=libc++<\/span>: <a href=\"https:\/\/en.wikipedia.org\/wiki\/LLVM\">LLVM<\/a> implementation of the standard library<\/li>\n<li><span style=\"font-family: courier new, courier;\">libcppcoro.a<\/span>: cppcoro library<\/li>\n<\/ul>\n<p>As I already mentioned: when cppcoro is in the future on C++20, you can use it with each compiler that supports C++20. Additionally, they give you a flavor for the concrete coroutines we may get with C++23.<\/p>\n<p>After a steep learning curve, I want to show you a few examples to cppcoro. I use existing code snippets or dig into the tests to present the various features of cppcoro. Let&#8217;s start with the coroutine types.<\/p>\n<h3>Coroutines Types<\/h3>\n<p>cppcoro has various kinds of tasks and generators.<\/p>\n<h4><span style=\"font-family: courier new, courier;\">task&lt;T&gt;<\/span><\/h4>\n<p>What is a task? Here is the definition, directly stolen from the documentation.<\/p>\n<ul>\n<li>A <strong>task<\/strong> represents an asynchronous computation executed lazily in that the execution of the coroutine does not start until the task is awaited.<\/li>\n<\/ul>\n<p>A task is a coroutine. In the following program, the function <span style=\"font-family: courier new, courier;\">main<\/span> waits for the function <span style=\"font-family: courier new, courier;\">first<\/span>, <span style=\"font-family: courier new, courier;\">first<\/span> waits for <span style=\"font-family: courier new, courier;\">second<\/span>, and <span style=\"font-family: courier new, courier;\">second<\/span> waits for the <span style=\"font-family: courier new, courier;\">third<\/span>.<\/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%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ cppcoroTask.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;chrono&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;thread&gt;<\/span>\n\n<span style=\"color: #009999;\">#include &lt;cppcoro\/sync_wait.hpp&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;cppcoro\/task.hpp&gt;<\/span>\n\n<span style=\"color: #006699; font-weight: bold;\">using<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>high_resolution_clock;\n<span style=\"color: #006699; font-weight: bold;\">using<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>time_point;\n<span style=\"color: #006699; font-weight: bold;\">using<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>duration;\n\n<span style=\"color: #006699; font-weight: bold;\">using<\/span> <span style=\"color: #006699; font-weight: bold;\">namespace<\/span> std<span style=\"color: #555555;\">::<\/span>chrono_literals; <span style=\"color: #0099ff; font-style: italic;\">\/\/ 1s<\/span>\n   \n<span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #cc00ff;\">getTimeSince<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> time_point<span style=\"color: #555555;\">&lt;<\/span>high_resolution_clock<span style=\"color: #555555;\">&gt;&amp;<\/span> start) {\n    \n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> end <span style=\"color: #555555;\">=<\/span> high_resolution_clock<span style=\"color: #555555;\">::<\/span>now();\n    duration<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">double<\/span><span style=\"color: #555555;\">&gt;<\/span> elapsed <span style=\"color: #555555;\">=<\/span> end <span style=\"color: #555555;\">-<\/span> start;\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> elapsed.count();\n    \n}\n\ncppcoro<span style=\"color: #555555;\">::<\/span>task<span style=\"color: #555555;\">&lt;&gt;<\/span> third(<span style=\"color: #006699; font-weight: bold;\">const<\/span> time_point<span style=\"color: #555555;\">&lt;<\/span>high_resolution_clock<span style=\"color: #555555;\">&gt;&amp;<\/span> start) {\n    \n    std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>sleep_for(<span style=\"color: #ff6600;\">1<\/span>s);\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Third waited \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> getTimeSince(start) <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" seconds.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n\n    co_return;                                                     <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\n        \n}\n\ncppcoro<span style=\"color: #555555;\">::<\/span>task<span style=\"color: #555555;\">&lt;&gt;<\/span> second(<span style=\"color: #006699; font-weight: bold;\">const<\/span> time_point<span style=\"color: #555555;\">&lt;<\/span>high_resolution_clock<span style=\"color: #555555;\">&gt;&amp;<\/span> start) {\n    \n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> thi <span style=\"color: #555555;\">=<\/span> third(start);                                       <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\n    std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>sleep_for(<span style=\"color: #ff6600;\">1<\/span>s);\n    co_await thi;                                                  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Second waited \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span>  getTimeSince(start) <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" seconds.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    \n}\n\ncppcoro<span style=\"color: #555555;\">::<\/span>task<span style=\"color: #555555;\">&lt;&gt;<\/span> first(<span style=\"color: #006699; font-weight: bold;\">const<\/span> time_point<span style=\"color: #555555;\">&lt;<\/span>high_resolution_clock<span style=\"color: #555555;\">&gt;&amp;<\/span> start) {\n    \n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> sec <span style=\"color: #555555;\">=<\/span> second(start);                                       <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\n    std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>sleep_for(<span style=\"color: #ff6600;\">1<\/span>s);\n    co_await sec;                                                   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"First waited \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span>  getTimeSince(start)  <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" seconds.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    \n}\n\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> main() {\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    \n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> start <span style=\"color: #555555;\">=<\/span> high_resolution_clock<span style=\"color: #555555;\">::<\/span>now();\n    cppcoro<span style=\"color: #555555;\">::<\/span>sync_wait(first(start));                              <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Main waited \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span>  getTimeSince(start) <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" seconds.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n\n}\n<\/pre>\n<\/div>\n<p>Admittedly, the program doesn&#8217;t do something meaningful, but it helps to understand the workflow of coroutines.<\/p>\n<p>First of all, the <span style=\"font-family: courier new, courier;\">main<\/span> function can&#8217;t be a coroutine. <span style=\"font-family: courier new, courier;\">cppcoro::sync_wait<\/span> (line 1) often serves, such as in this case, as a starting top-level task and waits until the task finishes. The coroutine <span style=\"font-family: courier new, courier;\">first<\/span>, such as all other coroutines, gets as an argument the <span style=\"font-family: courier new, courier;\">start<\/span> time and displays its execution time. What happens in the coroutine first? It starts the coroutine <span style=\"font-family: courier new, courier;\">second<\/span> (line 2), which is immediately paused, sleeps for a second, and resumes the coroutine via its handle <span style=\"font-family: courier new, courier;\">sec<\/span> in line (3). The coroutine <span style=\"font-family: courier new, courier;\">second<\/span> follows the same workflow but not the coroutine <span style=\"font-family: courier new, courier;\">third<\/span>. <span style=\"font-family: courier new, courier;\">third<\/span> is a coroutine that returns nothing and does not wait on another coroutine. When the<span style=\"font-family: courier new, courier;\"> third<\/span> is done, all other coroutines are executed. Consequentially, each coroutine takes 3 seconds.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5879\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroTask.png\" alt=\"cppcoroTask\" width=\"350\" height=\"228\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroTask.png 403w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroTask-300x195.png 300w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/p>\n<p>Let&#8217;s vary the program a little. What happens if the coroutines sleep after the <span style=\"font-family: courier new, courier;\">co_await<\/span> call?<\/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%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ cppcoroTask2.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;chrono&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;thread&gt;<\/span>\n\n<span style=\"color: #009999;\">#include &lt;cppcoro\/sync_wait.hpp&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;cppcoro\/task.hpp&gt;<\/span>\n\n<span style=\"color: #006699; font-weight: bold;\">using<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>high_resolution_clock;\n<span style=\"color: #006699; font-weight: bold;\">using<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>time_point;\n<span style=\"color: #006699; font-weight: bold;\">using<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>duration;\n\n<span style=\"color: #006699; font-weight: bold;\">using<\/span> <span style=\"color: #006699; font-weight: bold;\">namespace<\/span> std<span style=\"color: #555555;\">::<\/span>chrono_literals;\n\n<span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #cc00ff;\">getTimeSince<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> time_point<span style=\"color: #555555;\">&lt;::<\/span>high_resolution_clock<span style=\"color: #555555;\">&gt;&amp;<\/span> start) {\n    \n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> end <span style=\"color: #555555;\">=<\/span> high_resolution_clock<span style=\"color: #555555;\">::<\/span>now();\n    duration<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">double<\/span><span style=\"color: #555555;\">&gt;<\/span> elapsed <span style=\"color: #555555;\">=<\/span> end <span style=\"color: #555555;\">-<\/span> start;\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> elapsed.count();\n    \n}\n\ncppcoro<span style=\"color: #555555;\">::<\/span>task<span style=\"color: #555555;\">&lt;&gt;<\/span> third(<span style=\"color: #006699; font-weight: bold;\">const<\/span> time_point<span style=\"color: #555555;\">&lt;<\/span>high_resolution_clock<span style=\"color: #555555;\">&gt;&amp;<\/span> start) {\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Third waited \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> getTimeSince(start) <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" seconds.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>sleep_for(<span style=\"color: #ff6600;\">1<\/span>s);\n    co_return;\n        \n}\n\n\ncppcoro<span style=\"color: #555555;\">::<\/span>task<span style=\"color: #555555;\">&lt;&gt;<\/span> second(<span style=\"color: #006699; font-weight: bold;\">const<\/span> time_point<span style=\"color: #555555;\">&lt;<\/span>high_resolution_clock<span style=\"color: #555555;\">&gt;&amp;<\/span> start) {\n    \n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> thi <span style=\"color: #555555;\">=<\/span> third(start);\n    co_await thi;\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Second waited \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span>  getTimeSince(start) <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" seconds.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>sleep_for(<span style=\"color: #ff6600;\">1<\/span>s);\n    \n}\n\ncppcoro<span style=\"color: #555555;\">::<\/span>task<span style=\"color: #555555;\">&lt;&gt;<\/span> first(<span style=\"color: #006699; font-weight: bold;\">const<\/span> time_point<span style=\"color: #555555;\">&lt;<\/span>high_resolution_clock<span style=\"color: #555555;\">&gt;&amp;<\/span> start) {\n    \n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> sec <span style=\"color: #555555;\">=<\/span> second(start);\n    co_await sec;\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"First waited \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span>  getTimeSince(start)  <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" seconds.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>sleep_for(<span style=\"color: #ff6600;\">1<\/span>s);\n    \n}\n\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> main() {\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n \n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> start <span style=\"color: #555555;\">=<\/span> <span style=\"color: #555555;\">::<\/span>high_resolution_clock<span style=\"color: #555555;\">::<\/span>now();\n    \n    cppcoro<span style=\"color: #555555;\">::<\/span>sync_wait(first(start));\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Main waited \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span>  getTimeSince(start) <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" seconds.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n\n}\n<\/pre>\n<\/div>\n<p>You may have guessed it. The main function waits 3 seconds, but each iteratively invoked coroutine is one second less.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5880\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroTask2.png\" alt=\"cppcoroTask2\" width=\"350\" height=\"228\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroTask2.png 403w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroTask2-300x195.png 300w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/p>\n<p>In further posts, I add threads and signals to tasks.<\/p>\n<h3><span style=\"font-family: courier new, courier;\">generator&lt;T&gt;<\/span><\/h3>\n<p>Here is the definition from cppcoro.<\/p>\n<ul>\n<li>A <code>generator<\/code> represents a coroutine type that produces a sequence of values of type <code>T<\/code>, where values are produced lazily and synchronously.<\/li>\n<\/ul>\n<p>Without further ado, the program <span style=\"font-family: courier new, courier;\">cppcoroGenerator.cpp<\/span> shows two generators.<\/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%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ cppcoroGenerator.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;cppcoro\/generator.hpp&gt;<\/span>\n\ncppcoro<span style=\"color: #555555;\">::<\/span>generator<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">char<\/span><span style=\"color: #555555;\">&gt;<\/span> hello() {\n    co_yield <span style=\"color: #cc3300;\">'h'<\/span>;                  \n    co_yield <span style=\"color: #cc3300;\">'e'<\/span>;                   \n    co_yield <span style=\"color: #cc3300;\">'l'<\/span>;                   \n    co_yield <span style=\"color: #cc3300;\">'l'<\/span>;                   \n    co_yield <span style=\"color: #cc3300;\">'o'<\/span>;                   \n}\n\ncppcoro<span style=\"color: #555555;\">::<\/span>generator<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">long<\/span> <span style=\"color: #007788; font-weight: bold;\">long<\/span><span style=\"color: #555555;\">&gt;<\/span> fibonacci() {\n    <span style=\"color: #007788; font-weight: bold;\">long<\/span> <span style=\"color: #007788; font-weight: bold;\">long<\/span> a <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">0<\/span>;\n    <span style=\"color: #007788; font-weight: bold;\">long<\/span> <span style=\"color: #007788; font-weight: bold;\">long<\/span> b <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">1<\/span>;\n    <span style=\"color: #006699; font-weight: bold;\">while<\/span> (<span style=\"color: #336666;\">true<\/span>) {\n        co_yield b;                 <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\n        <span style=\"color: #006699; font-weight: bold;\">auto<\/span> tmp <span style=\"color: #555555;\">=<\/span> a;\n        a <span style=\"color: #555555;\">=<\/span> b;\n        b <span style=\"color: #555555;\">+=<\/span> tmp;\n    }\n}\n\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> main() {\n\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    \n    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #006699; font-weight: bold;\">auto<\/span> c<span style=\"color: #555555;\">:<\/span> hello()) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> c; \n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>;\n    \n    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #006699; font-weight: bold;\">auto<\/span> i<span style=\"color: #555555;\">:<\/span> fibonacci()) {  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\n        <span style=\"color: #006699; font-weight: bold;\">if<\/span> (i <span style=\"color: #555555;\">&gt; 1'000'000<\/span>) <span style=\"color: #006699; font-weight: bold;\">break<\/span>;\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> i <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" \"<\/span>;\n    }\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>;\n    \n}\n<\/pre>\n<\/div>\n<p>The first coroutine <span style=\"font-family: courier new, courier;\">hello<\/span> returns on request the next character; the coroutine <span style=\"font-family: courier new, courier;\">Fibonacci<\/span> the following Fibonacci number. <span style=\"font-family: courier new, courier;\">Fibonacci<\/span> creates an infinite data stream.\u00a0 What happens in line 1? The range-based for-loop triggers the execution of the coroutine. The first iteration starts the coroutines, returns the value at<span style=\"font-family: courier new, courier;\"> co_yield b<\/span>, and pauses. Subsequent calls of the range-based for-loop resume the coroutine <span style=\"font-family: courier new, courier;\">fibonacci<\/span> and return the next Fibonacci number.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5881\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroGenerator.png\" alt=\"cppcoroGenerator\" width=\"650\" height=\"122\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroGenerator.png 1259w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroGenerator-300x56.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroGenerator-1024x193.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/cppcoroGenerator-768x145.png 768w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<p>Before I end this post, I want to provide an intuition of the difference between <span style=\"font-family: courier new, courier;\">co_await<\/span> (task) and <span style=\"font-family: courier new, courier;\">co_yield<\/span> (generator): <strong><span style=\"font-family: courier new, courier;\">co_await<\/span> waits to the inside, <span style=\"font-family: courier new, courier;\">co_yiel<\/span>d waits to the outside<\/strong>. For example, the coroutine <span style=\"font-family: courier new, courier;\">first<\/span> waits for the called coroutine second (<span style=\"font-family: courier new, courier;\">cppcoroTask.cpp<\/span>), but the coroutine <span style=\"font-family: courier new, courier;\">fibonacci<\/span> (<span style=\"font-family: courier new, courier;\">cppcoroGenerator.cpp<\/span>) is triggered by the external range-based for-loop.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>My<a href=\"https:\/\/www.modernescpp.com\/index.php\/c-20-coroutine-abstraction-with-cppcoro\"> next post<\/a> to cppcoro dives deeper into tasks. I combine them with threads, signals, or thread pools.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The cppcoro library from Lewis Baker gives you what C++20 doesn&#8217;t: a library of C++ coroutine abstractions based on the coroutines TS.<\/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-5882","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\/5882","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=5882"}],"version-history":[{"count":2,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5882\/revisions"}],"predecessor-version":[{"id":8421,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5882\/revisions\/8421"}],"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=5882"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5882"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5882"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}