{"id":8692,"date":"2023-12-18T11:09:57","date_gmt":"2023-12-18T11:09:57","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=8692"},"modified":"2023-12-18T11:09:57","modified_gmt":"2023-12-18T11:09:57","slug":"a-coroutines-based-single-consumer-single-producer-workflow-by-ljubic-damir","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/a-coroutines-based-single-consumer-single-producer-workflow-by-ljubic-damir\/","title":{"rendered":"A Coroutines-Based Single Consumer &#8211; Single Producer Workflow by Ljubic Damir"},"content":{"rendered":"\n<p>I&#8217;m happy to present in this guest post by Ljubic Damir a typical use-case for coroutines:  a producer &#8211; consumer workflow.<\/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>Although this producer-consumer workflow is challenging, it is a nice starting point for your coroutine experiments.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Intro<\/h2>\n\n\n\n<p>Coroutines provide a more intuitive and structured way of writing asynchronous code by allowing you to write asynchronous operations in a procedural style. They are a feature introduced in C++20 to simplify asynchronous programming.<\/p>\n\n\n\n<p>Pre-existing mechanisms like <code>std::async<\/code> tasks, <code>std::packaged_task<\/code>, or events  (<code>std::condition_variable<\/code> &amp; <code>std::mutex<\/code>), synchronize two or more threads on the result of the task by establishing a communication channel. This communication channel has two ends:<\/p>\n\n\n\n<p>&#8211; <code><strong>std::promise<\/strong><\/code> that writes into the shared state either the result or the exception, and<\/p>\n\n\n\n<p>&#8211; <code><strong>std::future<\/strong><\/code> (<code>std::shared_future<\/code>) &#8211; a receiving end that waits on the result of the task (or the exception). <\/p>\n\n\n\n<p>Unlike this pre-existing mechanism, coroutines don\u2018t directly involve threads or other OS synchronization primitives. They are a pure software abstraction based on the coroutine&#8217;s control object and the <strong>state-machine<\/strong> logic built around it.<\/p>\n\n\n\n<p>Coroutines are <em>stackless<\/em> &#8211; which means that the control object has to be created on the heap. Coincidentally, it\u2018s a library wrapper around the <code>promise_type<\/code> (<code>std::coroutine_handle&lt;promise_type&gt;<\/code>), but it doesn\u2019t have anything in common with <code>std::promise<\/code>.<\/p>\n\n\n\n<p>The<strong> <code>promise_type<\/code><\/strong> is an interface (a <em>customization point<\/em>) that describes the predefined transition states in a coroutine&#8217;s state machine.<\/p>\n\n\n\n<p>Coroutines are highly versatile and can be used in various scenarios where you must manage asynchronous message flow. One common example is socket-based communication.<\/p>\n\n\n\n<p>Today, I\u2018ll try to enlighten coroutines through another example: <strong>single producer &#8211; single consumer<\/strong> workflow.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Implementation<\/h2>\n\n\n\n<p>First, we need to define <strong>result type<\/strong> for the coroutine<\/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\">class<\/span>[[<\/span><span style=\"color: #00AA88; font-weight: bold\">nodiscard<\/span>]] AudioDataResult final\n\n{\n\n    <span style=\"color: #9999FF\">public:<\/span>\n\n        <span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">promise_type<\/span>;\n\n        <span style=\"color: #006699; font-weight: bold\">using<\/span> handle_type <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;<\/span>promise_type<span style=\"color: #555555\">&gt;<\/span>;\n\n                \n\n        <span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">promise_type<\/span>\n\n        {\n\n            ...\n\n        };\n\n};\n<\/pre><\/div>\n\n\n\n<p>as a wrapper around the inner:<code><em> promise_type<\/em><\/code> type. We decorate the enclosing class with<code> [[nodiscard]]<\/code> attribute, since the result type is the control object of the coroutine that we return to the client code &#8211; to manage its suspension\/resumption.<\/p>\n\n\n\n<p><strong><em>@note The destructor of the class cleans the resources (dynamic memory) in RAII fashion, so strictly speaking, the return type could be ignored if there is no need to manage<\/em><\/strong><strong><em> the coroutine state<\/em><\/strong>.<\/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: #555555\">~<\/span>AudioDataResult() { <span style=\"color: #006699; font-weight: bold\">if<\/span>(handle_) { handle_.destroy(); } }\n<\/pre><\/div>\n\n\n\n<p>The result type is move-only: the copy operations are forbidden &#8211; to prevent the control object from being multiplicated.<\/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\">\/\/ Make the result type move-only, due to exclusive ownership over the handle<\/span>\n\nAudioDataResult(<span style=\"color: #006699; font-weight: bold\">const<\/span> AudioDataResult<span style=\"color: #555555\">&amp;<\/span> ) <span style=\"color: #555555\">=<\/span> <span style=\"color: #006699; font-weight: bold\">delete<\/span>;\n\nAudioDataResult<span style=\"color: #555555\">&amp;<\/span> <span style=\"color: #006699; font-weight: bold\">operator<\/span><span style=\"color: #555555\">=<\/span> (constAudioDataResult<span style=\"color: #555555\">&amp;<\/span> ) <span style=\"color: #555555\">=<\/span> <span style=\"color: #006699; font-weight: bold\">delete<\/span>;\n\n \n\nAudioDataResult(AudioDataResult<span style=\"color: #555555\">&amp;&amp;<\/span> other) noexcept<span style=\"color: #555555\">:<\/span>\n\nhandle_(std<span style=\"color: #555555\">::<\/span>exchange(other.handle_, nullptr))\n\n{}\n\n \n\nAudioDataResult<span style=\"color: #555555\">&amp;<\/span> <span style=\"color: #006699; font-weight: bold\">operator<\/span> <span style=\"color: #555555\">=<\/span> (AudioDataResult<span style=\"color: #555555\">&amp;&amp;<\/span> other) noexcept\n\n{\n\n    <span style=\"color: #006699; font-weight: bold\">using<\/span> <span style=\"color: #006699; font-weight: bold\">namespace<\/span> std;\n\n    AudioDataResult tmp <span style=\"color: #555555\">=<\/span>std<span style=\"color: #555555\">::<\/span>move(other);\n\n    swap(<span style=\"color: #555555\">*<\/span><span style=\"color: #006699; font-weight: bold\">this<\/span>, tmp);\n\n    <span style=\"color: #006699; font-weight: bold\">return<\/span> <span style=\"color: #555555\">*<\/span><span style=\"color: #006699; font-weight: bold\">this<\/span>;\n\n}\n<\/pre><\/div>\n\n\n\n<p>Let&#8217;s define the<code> promise_type<\/code> interface itself:<\/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\">\/\/ Predefined interface that has to be specify in order to implement<\/span>\n\n<span style=\"color: #0099FF; font-style: italic\">\/\/ coroutine&#39;s state-machine transitions<\/span>\n\n<span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">promise_type<\/span>\n\n{\n\n        \n\n    <span style=\"color: #9999FF\">public:<\/span>\n\n                \n\n        <span style=\"color: #006699; font-weight: bold\">using<\/span> value_type <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>vector<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span><span style=\"color: #555555\">&gt;<\/span>;\n\n \n\n        AudioDataResult <span style=\"color: #CC00FF\">get_return_object<\/span>()\n\n        {\n\n            <span style=\"color: #006699; font-weight: bold\">return<\/span> AudioDataResult{ handle_type<span style=\"color: #555555\">::<\/span>from_promise(<span style=\"color: #555555\">*<\/span><span style=\"color: #006699; font-weight: bold\">this<\/span>) };\n\n        }\n\n        std<span style=\"color: #555555\">::<\/span>suspend_never initial_suspend() noexcept { <span style=\"color: #006699; font-weight: bold\">return<\/span>{}; }\n\n        std<span style=\"color: #555555\">::<\/span>suspend_always final_suspend() noexcept { <span style=\"color: #006699; font-weight: bold\">return<\/span>{}; }\n\n        \n\n        <span style=\"color: #007788; font-weight: bold\">void<\/span> return_void() {}\n\n        <span style=\"color: #007788; font-weight: bold\">void<\/span> unhandled_exception()\n\n        {\n\n            std<span style=\"color: #555555\">::<\/span>rethrow_exception(std<span style=\"color: #555555\">::<\/span>current_exception());\n\n        }\n\n \n\n        <span style=\"color: #0099FF; font-style: italic\">\/\/ Generates the value and suspend the &quot;producer&quot;<\/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> Data<span style=\"color: #555555\">&gt;<\/span>\n\n        requires std<span style=\"color: #555555\">::<\/span>convertible_to<span style=\"color: #555555\">&lt;<\/span>std<span style=\"color: #555555\">::<\/span><span style=\"color: #007788; font-weight: bold\">decay_t<\/span><span style=\"color: #555555\">&lt;<\/span>Data<span style=\"color: #555555\">&gt;<\/span>, value_type<span style=\"color: #555555\">&gt;<\/span>\n\n        std<span style=\"color: #555555\">::<\/span>suspend_always yield_value(Data<span style=\"color: #555555\">&amp;&amp;<\/span> value)\n\n        {\n\n            data_ <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>forward<span style=\"color: #555555\">&lt;<\/span>Data<span style=\"color: #555555\">&gt;<\/span>(value);\n\n            data_ready_.store(<span style=\"color: #336666\">true<\/span>, std<span style=\"color: #555555\">::<\/span>memory_order<span style=\"color: #555555\">::<\/span>relaxed);\n\n            <span style=\"color: #006699; font-weight: bold\">return<\/span> {};\n\n        }\n\n \n\n    <span style=\"color: #9999FF\">private:<\/span>\n\n        value_type data_;\n\n        std<span style=\"color: #555555\">::<\/span>atomic<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">bool<\/span><span style=\"color: #555555\">&gt;<\/span> data_ready_;\n\n};<span style=\"color: #0099FF; font-style: italic\">\/\/promise_type interface<\/span>\n<\/pre><\/div>\n\n\n\n<p>The <code>promise_type<\/code> defines the necessary infrastructure of the coroutine. Additionally, for any coroutines that want to act as a generator &#8211; &#8220;<strong><em>producer<\/em><\/strong>&#8220;, to yield the values:<code> promise_type<\/code> has to be enhanced with the <code>yield_value<\/code> method (<code>co_yield \u2261 co_await promise_.yield_value<\/code>). Also, to resume the producer, at the point when provided data are consumed &#8211; we need to expose the appropriate wrapper method <code><em>resume<\/em>():<\/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: #007788; font-weight: bold\">void<\/span> <span style=\"color: #CC00FF\">resume<\/span>() { <span style=\"color: #006699; font-weight: bold\">if<\/span>( not handle_.done()) { handle_.resume();} }\n<\/pre><\/div>\n\n\n\n<p>Now &#8211; we need to extend the coroutine to support the <strong><em>consumer<\/em><\/strong> requirements: to be synchronized on the data readiness. In other words, the consumer will be suspended until the data are signaled as available by the producer. For that, we need to implement the Awaiter interface:<\/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\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">promise_type<\/span>\n\n{\n\n    <span style=\"color: #0099FF; font-style: italic\">\/\/ Awaiter interface: for consumer waiting on data being ready<\/span>\n\n    <span style=\"color: #006699; font-weight: bold\">struct<\/span> AudioDataAwaiter\n\n    {\n\n                                                \n\n        <span style=\"color: #006699; font-weight: bold\">explicit<\/span> AudioDataAwaiter(promise_type<span style=\"color: #555555\">&amp;<\/span> promise) noexcept<span style=\"color: #555555\">:<\/span> promise_(promise) {}\n\n \n\n        <span style=\"color: #007788; font-weight: bold\">bool<\/span> await_ready() <span style=\"color: #006699; font-weight: bold\">const<\/span>\n\n        {\n\n            <span style=\"color: #006699; font-weight: bold\">return<\/span> promise_.data_ready_.load(std<span style=\"color: #555555\">::<\/span>memory_order<span style=\"color: #555555\">::<\/span>relaxed);\n\n        }\n\n                                        \n\n        <span style=\"color: #007788; font-weight: bold\">void<\/span> await_suspend(handle_type) <span style=\"color: #006699; font-weight: bold\">const<\/span>\n\n        {\n\n            <span style=\"color: #006699; font-weight: bold\">while<\/span>( not promise_.data_ready_.exchange(<span style=\"color: #336666\">false<\/span>))\n\n            {\n\n                std<span style=\"color: #555555\">::<\/span>this_thread<span style=\"color: #555555\">::<\/span>yield();\n\n            }\n\n        }\n\n       \n\n        <span style=\"color: #0099FF; font-style: italic\">\/\/ move assignment at client invocation side:<\/span>\n\n        <span style=\"color: #0099FF; font-style: italic\">\/\/        const auto data = co_await audioDataResult;<\/span>\n\n        <span style=\"color: #0099FF; font-style: italic\">\/\/ This requires that coroutine&#39;s result type provides the co_await unary operator<\/span>\n\n \n\n        value_type<span style=\"color: #555555\">&amp;&amp;<\/span> await_resume() <span style=\"color: #006699; font-weight: bold\">const<\/span>\n\n        {\n\n            <span style=\"color: #006699; font-weight: bold\">return<\/span> std<span style=\"color: #555555\">::<\/span>move(promise_.data_);\n\n        }\n\n \n\n    <span style=\"color: #9999FF\">private:<\/span>\n\n            promise_type<span style=\"color: #555555\">&amp;<\/span> promise_;\n\n \n\n    };<span style=\"color: #0099FF; font-style: italic\">\/\/Awaiter interface<\/span>\n\n \n\n};<span style=\"color: #0099FF; font-style: italic\">\/\/promise_type<\/span>\n<\/pre><\/div>\n\n\n\n<p>In its state machine, the <em><code>await_ready()<\/code><\/em> will be the first transition state: it will be inspected on data readiness. If the data are not ready, as next the<em> <\/em><code>await_suspend()<\/code> will be called. Here we wait &#8211; until the matching flag is being set. Finally, the <em><code>await_resume()<\/code><\/em> will be called: we &#8220;move&#8221; the value from the<code> promise_type<\/code>, by unconditionally cast to the rvalue reference. On the client invocation side, this will cause the move assignment operator on the returned value &#8211; data to be called.<\/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\">const<\/span> <span style=\"color: #006699; font-weight: bold\">auto<\/span> data <span style=\"color: #555555\">=<\/span> co_await audioDataResult;\n<\/pre><\/div>\n\n\n\n<p>For that to work, the result type must provide the<code> co_await <\/code>unary operator, which returns our Awaiter interface.<\/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\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">AudioDataResult<\/span>\n\n{\n\n    <span style=\"color: #006699; font-weight: bold\">auto<\/span> <span style=\"color: #006699; font-weight: bold\">operator<\/span> co_await() noexcept\n\n    {\n\n        <span style=\"color: #006699; font-weight: bold\">return<\/span> promise_type<span style=\"color: #555555\">::<\/span>AudioDataAwaiter{handle_.promise()};\n\n    }\n\n};\n<\/pre><\/div>\n\n\n\n<p>&lt;Example 1&gt;: &nbsp;<a href=\"https:\/\/godbolt.org\/z\/MvYfbEP8r\">https:\/\/godbolt.org\/z\/MvYfbEP8r<\/a><\/p>\n\n\n\n<p>The following program <code>producerConsumer.cpp<\/code> shows a simplified version of example 1:<\/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\">\/\/ producerConsumer.cpp<\/span>\n\n<span style=\"color: #009999\">#include &lt;algorithm&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;atomic&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;chrono&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;iterator&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;memory&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;source_location&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;thread&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;utility&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;vector&gt;<\/span>\n\n\n<span style=\"color: #007788; font-weight: bold\">void<\/span> <span style=\"color: #CC00FF\">funcName<\/span>(<span style=\"color: #006699; font-weight: bold\">const<\/span> std<span style=\"color: #555555\">::<\/span>source_location location <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>source_location<span style=\"color: #555555\">::<\/span>current()) {\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> location.function_name() <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n}\n\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> Container<span style=\"color: #555555\">&gt;<\/span>\n<span style=\"color: #007788; font-weight: bold\">void<\/span> printContainer(<span style=\"color: #006699; font-weight: bold\">const<\/span> Container<span style=\"color: #555555\">&amp;<\/span> container)\n{\n    <span style=\"color: #006699; font-weight: bold\">typedef<\/span> <span style=\"color: #006699; font-weight: bold\">typename<\/span> Container<span style=\"color: #555555\">::<\/span>value_type value_type;\n    <span style=\"color: #006699; font-weight: bold\">auto<\/span> first <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>cbegin(container);\n    <span style=\"color: #006699; font-weight: bold\">auto<\/span> last <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>cend(container);\n\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot; [&quot;<\/span>;\n    std<span style=\"color: #555555\">::<\/span>copy(first, std<span style=\"color: #555555\">::<\/span>prev(last), std<span style=\"color: #555555\">::<\/span>ostream_iterator<span style=\"color: #555555\">&lt;<\/span>value_type<span style=\"color: #555555\">&gt;<\/span>(std<span style=\"color: #555555\">::<\/span>cout, <span style=\"color: #CC3300\">&quot;, &quot;<\/span>));\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #555555\">*<\/span>std<span style=\"color: #555555\">::<\/span>prev(last) <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>;\n}\n\n\n\n\n<span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #AA0000; background-color: #FFAAAA\">[[<\/span><span style=\"color: #00AA88; font-weight: bold\">nodiscard<\/span>]] AudioDataResult final\n{\n    <span style=\"color: #9999FF\">public:<\/span>\n        <span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">promise_type<\/span>;\n        <span style=\"color: #006699; font-weight: bold\">using<\/span> handle_type <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>coroutine_handle<span style=\"color: #555555\">&lt;<\/span>promise_type<span style=\"color: #555555\">&gt;<\/span>;\n        \n        <span style=\"color: #0099FF; font-style: italic\">\/\/ Predefined interface that has to be specify in order to implement<\/span>\n        <span style=\"color: #0099FF; font-style: italic\">\/\/ coroutine&#39;s state-machine transitions<\/span>\n        <span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">promise_type<\/span> \n        {\n            \n            <span style=\"color: #9999FF\">public:<\/span>\n                \n                <span style=\"color: #006699; font-weight: bold\">using<\/span> value_type <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>vector<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span><span style=\"color: #555555\">&gt;<\/span>;\n\n                AudioDataResult <span style=\"color: #CC00FF\">get_return_object<\/span>() \n                {\n                    <span style=\"color: #006699; font-weight: bold\">return<\/span> AudioDataResult{handle_type<span style=\"color: #555555\">::<\/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_never 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                <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                    std<span style=\"color: #555555\">::<\/span>rethrow_exception(std<span style=\"color: #555555\">::<\/span>current_exception());\n                }\n\n                <span style=\"color: #0099FF; font-style: italic\">\/\/ Generates the value and suspend the &quot;producer&quot;<\/span>\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> Data<span style=\"color: #555555\">&gt;<\/span>\n                requires std<span style=\"color: #555555\">::<\/span>convertible_to<span style=\"color: #555555\">&lt;<\/span>std<span style=\"color: #555555\">::<\/span><span style=\"color: #007788; font-weight: bold\">decay_t<\/span><span style=\"color: #555555\">&lt;<\/span>Data<span style=\"color: #555555\">&gt;<\/span>, value_type<span style=\"color: #555555\">&gt;<\/span>\n                std<span style=\"color: #555555\">::<\/span>suspend_always yield_value(Data<span style=\"color: #555555\">&amp;&amp;<\/span> value) \n                {\n                    data_ <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>forward<span style=\"color: #555555\">&lt;<\/span>Data<span style=\"color: #555555\">&gt;<\/span>(value);\n                    data_ready_.store(<span style=\"color: #336666\">true<\/span>);\n                    <span style=\"color: #006699; font-weight: bold\">return<\/span> {};\n                }\n\n                <span style=\"color: #0099FF; font-style: italic\">\/\/ Awaiter interface: for consumer waiting on data being ready<\/span>\n                <span style=\"color: #006699; font-weight: bold\">struct<\/span> AudioDataAwaiter \n                {\n                    <span style=\"color: #006699; font-weight: bold\">explicit<\/span> AudioDataAwaiter(promise_type<span style=\"color: #555555\">&amp;<\/span> promise) noexcept<span style=\"color: #555555\">:<\/span> promise_(promise) {}\n\n                    <span style=\"color: #007788; font-weight: bold\">bool<\/span> await_ready() <span style=\"color: #006699; font-weight: bold\">const<\/span> { <span style=\"color: #006699; font-weight: bold\">return<\/span> promise_.data_ready_.load();}\n                    \n                    <span style=\"color: #007788; font-weight: bold\">void<\/span> await_suspend(handle_type) <span style=\"color: #006699; font-weight: bold\">const<\/span>\n                    {\n                        <span style=\"color: #006699; font-weight: bold\">while<\/span>(not promise_.data_ready_.exchange(<span style=\"color: #336666\">false<\/span>)) {\n                             std<span style=\"color: #555555\">::<\/span>this_thread<span style=\"color: #555555\">::<\/span>yield(); \n                        }\n                    }\n                    <span style=\"color: #0099FF; font-style: italic\">\/\/ move assignment at client invocation side: const auto data = co_await audioDataResult;<\/span>\n                    <span style=\"color: #0099FF; font-style: italic\">\/\/ This requires that coroutine&#39;s result type provides the co_await unary operator<\/span>\n                    value_type<span style=\"color: #555555\">&amp;&amp;<\/span> await_resume() <span style=\"color: #006699; font-weight: bold\">const<\/span> \n                    {\n                        <span style=\"color: #006699; font-weight: bold\">return<\/span> std<span style=\"color: #555555\">::<\/span>move(promise_.data_);\n                    }\n\n                    <span style=\"color: #9999FF\">private:<\/span> \n                        promise_type<span style=\"color: #555555\">&amp;<\/span> promise_;\n                };<span style=\"color: #0099FF; font-style: italic\">\/\/Awaiter interface<\/span>\n\n        \n            <span style=\"color: #9999FF\">private:<\/span>\n                value_type data_;\n                std<span style=\"color: #555555\">::<\/span>atomic<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">bool<\/span><span style=\"color: #555555\">&gt;<\/span> data_ready_;\n        }; <span style=\"color: #0099FF; font-style: italic\">\/\/promise_type interface<\/span>\n\n        \n        <span style=\"color: #006699; font-weight: bold\">auto<\/span> <span style=\"color: #006699; font-weight: bold\">operator<\/span> co_await() noexcept   \n        {\n            <span style=\"color: #006699; font-weight: bold\">return<\/span> promise_type<span style=\"color: #555555\">::<\/span>AudioDataAwaiter{handle_.promise()};\n        }\n\n        <span style=\"color: #0099FF; font-style: italic\">\/\/ Make the result type move-only, due to ownership over the handle<\/span>\n        AudioDataResult(<span style=\"color: #006699; font-weight: bold\">const<\/span> AudioDataResult<span style=\"color: #555555\">&amp;<\/span>) <span style=\"color: #555555\">=<\/span> <span style=\"color: #006699; font-weight: bold\">delete<\/span>;\n        AudioDataResult<span style=\"color: #555555\">&amp;<\/span> <span style=\"color: #006699; font-weight: bold\">operator<\/span><span style=\"color: #555555\">=<\/span>(<span style=\"color: #006699; font-weight: bold\">const<\/span> AudioDataResult<span style=\"color: #555555\">&amp;<\/span>) <span style=\"color: #555555\">=<\/span> <span style=\"color: #006699; font-weight: bold\">delete<\/span>;\n\n        AudioDataResult(AudioDataResult<span style=\"color: #555555\">&amp;&amp;<\/span> other) noexcept<span style=\"color: #555555\">:<\/span> handle_(std<span style=\"color: #555555\">::<\/span>exchange(other.handle_, nullptr)){}\n        AudioDataResult<span style=\"color: #555555\">&amp;<\/span> <span style=\"color: #006699; font-weight: bold\">operator<\/span><span style=\"color: #555555\">=<\/span>(AudioDataResult<span style=\"color: #555555\">&amp;&amp;<\/span> other) noexcept \n        {\n            <span style=\"color: #006699; font-weight: bold\">using<\/span> <span style=\"color: #006699; font-weight: bold\">namespace<\/span> std;\n            AudioDataResult tmp <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>move(other);\n            swap(<span style=\"color: #555555\">*<\/span><span style=\"color: #006699; font-weight: bold\">this<\/span>, tmp);\n            <span style=\"color: #006699; font-weight: bold\">return<\/span> <span style=\"color: #555555\">*<\/span><span style=\"color: #006699; font-weight: bold\">this<\/span>;\n        }\n\n        <span style=\"color: #0099FF; font-style: italic\">\/\/ d-tor: RAII<\/span>\n        <span style=\"color: #555555\">~<\/span>AudioDataResult() { <span style=\"color: #006699; font-weight: bold\">if<\/span> (handle_) {funcName(); handle_.destroy();}}\n\n        <span style=\"color: #0099FF; font-style: italic\">\/\/ For resuming the producer - at the point when the data are consumed<\/span>\n        <span style=\"color: #007788; font-weight: bold\">void<\/span> resume() {<span style=\"color: #006699; font-weight: bold\">if<\/span> (not handle_.done()) { funcName(); handle_.resume();}}\n    \n    <span style=\"color: #9999FF\">private:<\/span>\n        AudioDataResult(handle_type handle) noexcept <span style=\"color: #555555\">:<\/span> handle_(handle) {}\n\n    <span style=\"color: #9999FF\">private:<\/span>\n    handle_type handle_;\n};\n\n\n<span style=\"color: #006699; font-weight: bold\">using<\/span> data_type <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>vector<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span><span style=\"color: #555555\">&gt;<\/span>;\nAudioDataResult <span style=\"color: #CC00FF\">producer<\/span>(<span style=\"color: #006699; font-weight: bold\">const<\/span> data_type<span style=\"color: #555555\">&amp;<\/span> data) \n{\n    <span style=\"color: #006699; font-weight: bold\">for<\/span> (std<span style=\"color: #555555\">::<\/span><span style=\"color: #007788; font-weight: bold\">size_t<\/span> i <span style=\"color: #555555\">=<\/span> <span style=\"color: #FF6600\">0<\/span>; i <span style=\"color: #555555\">&lt;<\/span> <span style=\"color: #FF6600\">5<\/span>; <span style=\"color: #555555\">++<\/span>i) {\n        funcName();\n        co_yield data;\n    }\n    co_yield data_type{}; <span style=\"color: #0099FF; font-style: italic\">\/\/ exit criteria<\/span>\n}\n\nAudioDataResult <span style=\"color: #CC00FF\">consumer<\/span>(AudioDataResult<span style=\"color: #555555\">&amp;<\/span> audioDataResult) \n{\n    <span style=\"color: #006699; font-weight: bold\">while<\/span>(<span style=\"color: #336666\">true<\/span>)\n    {\n        funcName();\n        <span style=\"color: #006699; font-weight: bold\">const<\/span> <span style=\"color: #006699; font-weight: bold\">auto<\/span> data <span style=\"color: #555555\">=<\/span> co_await audioDataResult;\n        <span style=\"color: #006699; font-weight: bold\">if<\/span> (data.empty()) {std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;No data - exit!<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/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> <span style=\"color: #CC3300\">&quot;Data received:&quot;<\/span>;\n        printContainer(data);\n        audioDataResult.resume(); <span style=\"color: #0099FF; font-style: italic\">\/\/ resume producer<\/span>\n    }\n}\n\n<span style=\"color: #007788; font-weight: bold\">int<\/span> <span style=\"color: #CC00FF\">main<\/span>() \n{\n    {\n        <span style=\"color: #006699; font-weight: bold\">const<\/span> data_type data <span style=\"color: #555555\">=<\/span> {<span style=\"color: #FF6600\">1<\/span>, <span style=\"color: #FF6600\">2<\/span>, <span style=\"color: #FF6600\">3<\/span>, <span style=\"color: #FF6600\">4<\/span>};\n        <span style=\"color: #006699; font-weight: bold\">auto<\/span> audioDataProducer <span style=\"color: #555555\">=<\/span> producer(data);\n        std<span style=\"color: #555555\">::<\/span><span style=\"color: #006699; font-weight: bold\">thread<\/span> t ([<span style=\"color: #555555\">&amp;<\/span>]{<span style=\"color: #006699; font-weight: bold\">auto<\/span> audioRecorded <span style=\"color: #555555\">=<\/span> consumer(audioDataProducer);});\n        t.join();\n    }\n\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;bye-bye!<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n}\n<\/pre><\/div>\n\n\n\n<p>Finally, here is the output of the program:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"472\" height=\"640\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/producerConsumer.png\" alt=\"\" class=\"wp-image-8705\" style=\"width:400px\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/producerConsumer.png 472w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2023\/11\/producerConsumer-221x300.png 221w\" sizes=\"auto, (max-width: 472px) 100vw, 472px\" \/><\/figure>\n\n\n\n<p>The other way around is to use the <code>promise_type::await_transform()<\/code> &#8211; to wait on the value stored in the <code>promise_type<\/code> instance used by the producer.<\/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\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">promise_type<\/span>\n\n{\n\n    <span style=\"color: #006699; font-weight: bold\">auto<\/span> await_transform(handle_type other)\n\n    {\n\n        <span style=\"color: #0099FF; font-style: italic\">\/\/ Awaiter interface: remained the same<\/span>\n\n        <span style=\"color: #006699; font-weight: bold\">struct<\/span> AudioDataAwaiter\n\n        {\n\n            <span style=\"color: #006699; font-weight: bold\">explicit<\/span> AudioDataAwaiter(promise_type<span style=\"color: #555555\">&amp;<\/span> promise)noexcept<span style=\"color: #555555\">:<\/span> promise_(promise) {}\n\n            ...\n\n        };\n\n    \n\n        <span style=\"color: #006699; font-weight: bold\">return<\/span> AudioDataAwaiter{other.promise()};\n\n    }\n\n};\n<\/pre><\/div>\n\n\n\n<p>This way, we don&#8217;t need to specify the <code>co_await<\/code> unary operator of the result type anymore, but rather (explicit) conversion operator<\/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\">explicit<\/span> <span style=\"color: #006699; font-weight: bold\">operator<\/span> handle_type() <span style=\"color: #006699; font-weight: bold\">const<\/span> {<span style=\"color: #006699; font-weight: bold\">return<\/span> handle_;}\n<\/pre><\/div>\n\n\n\n<p>so that we can pass it at the point when the consumer calls <code>co_await<\/code>, which will internally be translated to the <code>await_transform()<\/code> call.<\/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\">const<\/span> <span style=\"color: #006699; font-weight: bold\">auto<\/span> data <span style=\"color: #555555\">=<\/span> co_await <span style=\"color: #006699; font-weight: bold\">static_cast<\/span><span style=\"color: #555555\">&lt;<\/span>AudioDataResult<span style=\"color: #555555\">::<\/span>handle_type<span style=\"color: #555555\">&gt;<\/span>(audioDataResult);\n<\/pre><\/div>\n\n\n\n<p>We can illustrate this as:&nbsp;&nbsp; <em><code>me.handle_.promise().await_transform(other.handle_)<\/code><\/em><\/p>\n\n\n\n<p>&lt;Example 2&gt;: &nbsp;<a href=\"https:\/\/godbolt.org\/z\/57zsK9rEn\">https:\/\/godbolt.org\/z\/57zsK9rEn<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>In this simple example, the producer will be suspended without any penalty &#8211; since, after being resumed, it will provide the very same &#8211; upfront known sequence of data. In a real scenario, that is likely not the case: the producer will probably be some kind of mediator &#8211; receiver of asynchronously emitted data that will be retransmitted to the consumer. For that, some queuing logic needs to be implemented at the producer side to avoid the data loss at the point of being suspended, waiting for the consumer to resume it &#8211; to compensate for the differences in producer data arrival vs. consumer consumption rate.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What&#8217;s Next? <\/h2>\n\n\n\n<p>In C++20, you can define or <code>default<\/code> the three-way comparison operator.  This gives you all six comparison operators:<code> ==, !=, &lt;, &lt;=, &gt;<\/code>, and <code>&gt;=<\/code>. Do you know that you can also define or <code>default<\/code> the equal operator (<code>==)<\/code> ?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Short Christmas Break<\/h2>\n\n\n\n<p>My blog makes a short Christmas break. The next post will be published on the 8th January 2024. Have a good time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;m happy to present in this guest post by Ljubic Damir a typical use-case for coroutines: a producer &#8211; consumer workflow. Although this producer-consumer workflow is challenging, it is a nice starting point for your coroutine experiments. Intro Coroutines provide a more intuitive and structured way of writing asynchronous code by allowing you to write [&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-8692","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\/8692","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=8692"}],"version-history":[{"count":26,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8692\/revisions"}],"predecessor-version":[{"id":8801,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/8692\/revisions\/8801"}],"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=8692"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=8692"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=8692"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}