{"id":5875,"date":"2020-04-10T05:58:25","date_gmt":"2020-04-10T05:58:25","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-20-thread-synchronization-with-coroutines\/"},"modified":"2023-09-28T07:44:00","modified_gmt":"2023-09-28T07:44:00","slug":"c-20-thread-synchronization-with-coroutines","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-20-thread-synchronization-with-coroutines\/","title":{"rendered":"C++20: Thread Synchronization with Coroutines"},"content":{"rendered":"<p>It&#8217;s a typical requirement for thread management to synchronize them. One thread prepares, in this case, a work-package another thread is waiting for.<\/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>I assume most of you use condition variables for this sender\/receiver or producer\/consumer workflow. Condition variables have many inherent risks, such as spurious wakeup and lost wakeup. Before I implement thread synchronization with coroutines, let me rephrase from a previous post about the inherent challenges of condition variables.<\/p>\n<h2>The Challenges of Condition Variables<\/h2>\n<p>Here is the pattern for the correct usage of condition variables.<\/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;\">\/\/ conditionVariables.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;condition_variable&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;thread&gt;<\/span>\n\nstd<span style=\"color: #555555;\">::<\/span>mutex mutex_;\nstd<span style=\"color: #555555;\">::<\/span>condition_variable condVar; \n\n<span style=\"color: #007788; font-weight: bold;\">bool<\/span> dataReady{<span style=\"color: #336666;\">false<\/span>};\n\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">waitingForWork<\/span>(){\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Waiting \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    std<span style=\"color: #555555;\">::<\/span>unique_lock<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>mutex<span style=\"color: #555555;\">&gt;<\/span> lck(mutex_);\n    condVar.wait(lck, []{ <span style=\"color: #006699; font-weight: bold;\">return<\/span> dataReady; });   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Running \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n}\n\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">setDataReady<\/span>(){\n    {\n        std<span style=\"color: #555555;\">::<\/span>lock_guard<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>mutex<span style=\"color: #555555;\">&gt;<\/span> lck(mutex_);\n        dataReady <span style=\"color: #555555;\">=<\/span> <span style=\"color: #336666;\">true<\/span>;\n    }\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Data prepared\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    condVar.notify_one();                        <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\n}\n\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>(){\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  std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t1(waitingForWork);               <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\n  std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2(setDataReady);                 <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\n\n  t1.join();\n  t2.join();\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>How does the synchronization work? The program has two child threads:<span style=\"font-family: 'courier new', courier;\"> t1<\/span> and <span style=\"font-family: 'courier new', courier;\">t2<\/span>. They get their work package<span style=\"font-family: 'courier new', courier;\">\u00a0waitingForWork<\/span>\u00a0and <span style=\"font-family: 'courier new', courier;\">setDataRead<\/span>\u00a0in lines (1 and 2). <span style=\"font-family: 'courier new', courier;\">setDataReady<\/span>\u00a0notifies &#8211; using the condition variable <span style=\"font-family: 'courier new', courier;\">condVar<\/span>\u00a0&#8211; that it is done with preparing the work: <span style=\"font-family: 'courier new', courier;\">condVar.notify_one()<\/span>(line 3). While holding the lock, thread <span style=\"font-family: 'courier new', courier;\">t1<\/span>\u00a0waits for its notification: <span style=\"font-family: 'courier new', courier;\">condVar.wait(lck, []{ return dataReady; })<\/span>( line 4). The sender and receiver need a lock. In the case of the sender a <span style=\"font-family: 'courier new', courier;\">std::lock_guard<\/span>\u00a0is sufficient because it calls lock and unlock only once. In the case of the receiver, a <span style=\"font-family: 'courier new', courier;\">std::unique_lock<\/span>\u00a0is necessary because it usually frequently locks and unlocks its mutex.<\/p>\n<p>Finally, the output of the program.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-4756\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/05\/conditionVariable.png\" alt=\"conditionVariable\" width=\"400\" height=\"197\" \/><\/p>\n<p>Maybe you are wondering why you need a predicate for the <span style=\"font-family: 'courier new', courier;\">wait<\/span> call because you can invoke <span style=\"font-family: 'courier new', courier;\">wait<\/span>\u00a0without a predicate. This workflow seems quite too complicated for such a simple synchronization of threads.<\/p>\n<p>Now we are back to the missing memory condition variables and the two phenomena called lost wakeup and spurious wakeup.<\/p>\n<h3>Lost Wakeup and Spurious Wakeup<\/h3>\n<ul>\n<li><strong>Lost wakeup<\/strong>:\u00a0The sender sends its notification before the receiver is in the wait state. The consequence is that the notification is lost.<\/li>\n<li><strong>Spurious wakeup<\/strong>: The receiver may wake up although no notification has happened.<\/li>\n<\/ul>\n<p>To become not the victim of these two issues, you have to use an additional predicate as memory. If not, you have, in this example, a 50\/50 chance of a lost wakeup. A lost wakeup is essentially a deadlock because a thread waits for something that never happens.<\/p>\n<p>This is not the end of the traps you can fall into with condition variables. Read the details in the previous post: <a style=\"background-color: #ffffff; color: #00466e; text-decoration: underline; outline: 0px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; font-style: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;\" href=\"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-be-aware-of-the-traps-of-condition-variables\">C++ Core Guidelines: Be Aware of the Traps of Condition Variables<\/a>.<\/p>\n<p>Thanks to coroutines, thread synchronization is relatively easy\u00a0without the inherent risks of condition variables such as spurious wakeups and lost wakeups.<\/p>\n<h2>Thread Synchronization with <span style=\"font-family: 'courier new', courier;\">co_await<\/span><\/h2>\n<p><!-- HTML generated using hilite.me --><\/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;\">\/\/ senderReceiver.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;coroutine&gt;<\/span>\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;functional&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;stdexcept&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;atomic&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;thread&gt;<\/span>\n\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Event<\/span> {\n <span style=\"color: #9999ff;\">public:<\/span>\n\n    Event() <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">default<\/span>;\n\n    Event(<span style=\"color: #006699; font-weight: bold;\">const<\/span> Event<span style=\"color: #555555;\">&amp;<\/span>) <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">delete<\/span>;\n    Event(Event<span style=\"color: #555555;\">&amp;&amp;<\/span>) <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">delete<\/span>;\n    Event<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> Event<span style=\"color: #555555;\">&amp;<\/span>) <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">delete<\/span>;\n    Event<span style=\"color: #555555;\">&amp;<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span><span style=\"color: #555555;\">=<\/span>(Event<span style=\"color: #555555;\">&amp;&amp;<\/span>) <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">delete<\/span>;\n\n    <span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Awaiter<\/span>;\n    Awaiter <span style=\"color: #006699; font-weight: bold;\">operator<\/span> co_await() <span style=\"color: #006699; font-weight: bold;\">const<\/span> noexcept;\n\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> notify() noexcept;\n\n <span style=\"color: #9999ff;\">private:<\/span>\n\n    <span style=\"color: #006699; font-weight: bold;\">friend<\/span> <span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Awaiter<\/span>;\n  \n    <span style=\"color: #006699; font-weight: bold;\">mutable<\/span> std<span style=\"color: #555555;\">::<\/span>atomic<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">void<\/span><span style=\"color: #555555;\">*&gt;<\/span> suspendedWaiter{nullptr};\n    <span style=\"color: #006699; font-weight: bold;\">mutable<\/span> 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> notified{<span style=\"color: #336666;\">false<\/span>};\n\n};\n\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Event<\/span><span style=\"color: #555555;\">::<\/span>Awaiter {\n <span style=\"color: #9999ff;\">public:<\/span>\n  Awaiter(<span style=\"color: #006699; font-weight: bold;\">const<\/span> Event<span style=\"color: #555555;\">&amp;<\/span> eve)<span style=\"color: #555555;\">:<\/span> event(eve) {}\n\n  <span style=\"color: #007788; font-weight: bold;\">bool<\/span> await_ready() <span style=\"color: #006699; font-weight: bold;\">const<\/span>;\n  <span style=\"color: #007788; font-weight: bold;\">bool<\/span> await_suspend(std<span style=\"color: #555555;\">::<\/span>coroutine_handle<span style=\"color: #555555;\">&lt;&gt;<\/span> corHandle) noexcept;\n  <span style=\"color: #007788; font-weight: bold;\">void<\/span> await_resume() noexcept {}\n\n <span style=\"color: #9999ff;\">private:<\/span>\n    <span style=\"color: #006699; font-weight: bold;\">friend<\/span> <span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Event<\/span>;\n\n    <span style=\"color: #006699; font-weight: bold;\">const<\/span> Event<span style=\"color: #555555;\">&amp;<\/span> event;\n    std<span style=\"color: #555555;\">::<\/span>coroutine_handle<span style=\"color: #555555;\">&lt;&gt;<\/span> coroutineHandle;\n};\n\n<span style=\"color: #007788; font-weight: bold;\">bool<\/span> Event<span style=\"color: #555555;\">::<\/span>Awaiter<span style=\"color: #555555;\">::<\/span>await_ready() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {                            <span style=\"color: #0099ff; font-style: italic;\">\/\/ (7)<\/span>\n  \n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ allow at most one waiter<\/span>\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> (event.suspendedWaiter.load() <span style=\"color: #555555;\">!=<\/span> nullptr){\n        <span style=\"color: #006699; font-weight: bold;\">throw<\/span> std<span style=\"color: #555555;\">::<\/span>runtime_error(<span style=\"color: #cc3300;\">\"More than one waiter is not valid\"<\/span>);\n    }\n  \n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ event.notified == false; suspends the coroutine<\/span>\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ event.notified == true; the coroutine is executed such as a usual function<\/span>\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> event.notified;\n}\n<span style=\"color: #0099ff; font-style: italic;\">                                                                     \/\/ (8)<\/span>\n<span style=\"color: #007788; font-weight: bold;\">bool<\/span> Event<span style=\"color: #555555;\">::<\/span>Awaiter<span style=\"color: #555555;\">::<\/span>await_suspend(std<span style=\"color: #555555;\">::<\/span>coroutine_handle<span style=\"color: #555555;\">&lt;&gt;<\/span> corHandle) noexcept {\n\n    coroutineHandle <span style=\"color: #555555;\">=<\/span> corHandle;                                    \n  \n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> (event.notified) <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #336666;\">false<\/span>;\n  \n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ store the waiter for later notification<\/span>\n    event.suspendedWaiter.store(<span style=\"color: #006699; font-weight: bold;\">this<\/span>);\n\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #336666;\">true<\/span>;\n}\n\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> Event<span style=\"color: #555555;\">::<\/span>notify() noexcept {                                        <span style=\"color: #0099ff; font-style: italic;\">\/\/ (6)<\/span>\n    notified <span style=\"color: #555555;\">=<\/span> <span style=\"color: #336666;\">true<\/span>;\n  \n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ try to load the waiter<\/span>\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">*<\/span> waiter <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">static_cast<\/span><span style=\"color: #555555;\">&lt;<\/span>Awaiter<span style=\"color: #555555;\">*&gt;<\/span>(suspendedWaiter.load());\n \n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ check if a waiter is available<\/span>\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> (waiter <span style=\"color: #555555;\">!=<\/span> nullptr) {\n        <span style=\"color: #0099ff; font-style: italic;\">\/\/ resume the coroutine =&gt; await_resume<\/span>\n        waiter<span style=\"color: #555555;\">-&gt;<\/span>coroutineHandle.resume();\n    }\n}\n\nEvent<span style=\"color: #555555;\">::<\/span>Awaiter Event<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">operator<\/span> co_await() <span style=\"color: #006699; font-weight: bold;\">const<\/span> noexcept {\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> Awaiter{ <span style=\"color: #555555;\">*<\/span><span style=\"color: #006699; font-weight: bold;\">this<\/span> };\n}\n\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Task {\n    <span style=\"color: #006699; font-weight: bold;\">struct<\/span> promise_type {\n        Task get_return_object() { <span style=\"color: #006699; font-weight: bold;\">return<\/span> {}; }\n        std<span style=\"color: #555555;\">::<\/span>suspend_never initial_suspend() { <span style=\"color: #006699; font-weight: bold;\">return<\/span> {}; }\n        std<span style=\"color: #555555;\">::<\/span>suspend_never final_suspend() { <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};\n\nTask <span style=\"color: #cc00ff;\">receiver<\/span>(Event<span style=\"color: #555555;\">&amp;<\/span> event) {                                        <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> start <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>high_resolution_clock<span style=\"color: #555555;\">::<\/span>now();\n    co_await event;                                                 \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Got the notification! \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> end <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>high_resolution_clock<span style=\"color: #555555;\">::<\/span>now();\n    std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>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    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Waited \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> elapsed.count() <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<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: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>(){\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    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Notification before waiting\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    Event event1{};\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> senderThread1 <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span>([<span style=\"color: #555555;\">&amp;<\/span>event1]{ event1.notify(); });  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> receiverThread1 <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span>(receiver, std<span style=\"color: #555555;\">::<\/span>ref(event1));   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\n    \n    receiverThread1.join();\n    senderThread1.join();\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    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Notification after 2 seconds waiting\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\n    Event event2{};\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> receiverThread2 <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span>(receiver, std<span style=\"color: #555555;\">::<\/span>ref(event2));  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (5)<\/span>\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> senderThread2 <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span>([<span style=\"color: #555555;\">&amp;<\/span>event2]{\n      std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>sleep_for(<span style=\"color: #ff6600;\">2<\/span>s);\n      event2.notify();                                               <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\n    });\n    \n    receiverThread2.join();\n    senderThread2.join();\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>Thread synchronization with coroutines is straightforward from the user&#8217;s perspective. Let\u2019s have a look at\u00a0the program <span style=\"font-family: 'courier new', courier;\">senderReiver.cpp<\/span>. The threads<span style=\"font-family: 'courier new', courier;\"> senderThread1<\/span> (line 1) and senderThread2 (line 2)\u00a0use an event to send its notification. The function receiver in line (3) is the coroutine which is executed in the thread <span style=\"font-family: 'courier new', courier;\">receiverThread1<\/span> (line 4) and <span style=\"font-family: 'courier new', courier;\">receiverThread2<\/span>\u00a0(line 5). I measured the time between the coroutine&#8217;s beginning and end and displayed it.\u00a0This number shows how long the coroutine waits. The following screenshot displays the output of the\u00a0program with the\u00a0<a href=\"https:\/\/wandbox.org\/permlink\/qClEIVff0OXp51Av\">Wandbox<\/a>. The Compiler Explorer does not support thread creation, but Matt is &#8220;on it&#8221;.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5874\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/senderReceiver.png\" alt=\"senderReceiver\" width=\"500\" height=\"293\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/senderReceiver.png 531w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/04\/senderReceiver-300x175.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p>The output displays that the execution of the second coroutine takes about two seconds. The reason\u00a0is that\u00a0<span style=\"font-family: 'courier new', courier;\">event1<\/span> sends its notification (line 1) before the coroutine is suspended, but <span style=\"font-family: 'courier new', courier;\">event2<\/span>\u00a0sends its notification after a time duration of 2 seconds (line 2).<\/p>\n<p>Now, I put the implementer&#8217;s hat on and give you a rough idea of the workflow of the coroutine framework.<\/p>\n<h3>The simplified workflow<\/h3>\n<p>There is a subtle difference if you compare the class Generator in the last post (C++20: An Infinite Data Stream with Coroutines) with the class Event in this example. In the first case, the <span style=\"font-family: 'courier new', courier;\">Generator<\/span> is the awaitable and the awaiter, in the\u00a0second case, the Event uses the operator <span style=\"font-family: 'courier new', courier;\">co_await<\/span> to return the awaiter. This separation of concerns\u00a0into the awaitable and the awaiter improves the structure of the code.<\/p>\n<p>In my explanation of both workflows, I assume in the first case, the event\u00a0notification happens before the coroutine awaits the events. For the second case,\u00a0I assume it is the other way around.<\/p>\n<p>Let\u2019s first look at <span style=\"font-family: 'courier new', courier;\">event1<\/span> and the first workflow. <span style=\"font-family: 'courier new', courier;\">event1<\/span> send its notification before <span style=\"font-family: 'courier new', courier;\">receiverThread1\u00a0<\/span>is started. The call <span style=\"font-family: 'courier new', courier;\">event1<\/span> (line 1) triggers the member function\u00a0<span style=\"font-family: 'courier new', courier;\">notify<\/span> (line 6). First, the notification\u00a0flag is set, and then, the call <span style=\"font-family: 'courier new', courier;\">auto* waiter = static_cast&lt;awaiter*&gt;(suspendedWaiter.load());\u00a0<\/span>loads the potential waiter. In this case, the waiter is a <span style=\"font-family: 'courier new', courier;\">nullptr<\/span> because it was not set before. This\u00a0means the following resume call on the waiter is not executed. The subsequentially\u00a0performed function <span style=\"font-family: 'courier new', courier;\">await_ready<\/span> (line 7) checks first if there is more than one waiter. In\u00a0this case, I throw, for simplicity reasons, a <span style=\"font-family: 'courier new', courier;\">std::runtime<\/span> exception. The crucial part of this member function is the return value.\u00a0<span style=\"font-family: 'courier new', courier;\">event.notification<\/span> was already set to true in the notify method. <span style=\"font-family: 'courier new', courier;\">true<\/span> means that the\u00a0coroutine is not suspended and executes such as a usual function.<\/p>\n<p>In the second workflow, the <span style=\"font-family: 'courier new', courier;\">co_await event2<\/span> call happens before <span style=\"font-family: 'courier new', courier;\">event2<\/span> sends its notification.\u00a0<span style=\"font-family: 'courier new', courier;\">co_wait event2<\/span> triggers the call <span style=\"font-family: 'courier new', courier;\">await_ready<\/span> (line 7). The big difference to the first workflow is now\u00a0that <span style=\"font-family: 'courier new', courier;\">event.notified<\/span> is <span style=\"font-family: 'courier new', courier;\">false<\/span>. This <span style=\"font-family: 'courier new', courier;\">false<\/span> value causes the suspension of the coroutine. Technically\u00a0the member function\u00a0<span style=\"font-family: 'courier new', courier;\">await_suspend<\/span> (lines 8) is executed. <span style=\"font-family: 'courier new', courier;\">await_suspend<\/span> gets the coroutine handle\u00a0<span style=\"font-family: 'courier new', courier;\">corHandle<\/span> and stores it for later invocation in the variable <span style=\"font-family: 'courier new', courier;\">coroutineHandle<\/span>. Of course,\u00a0later invocation means resumption. Secondly, the waiter is stored in the variable <span style=\"font-family: 'courier new', courier;\">suspendedWaiter<\/span>.\u00a0When later <span style=\"font-family: 'courier new', courier;\">event2.notify<\/span> triggers its notification, the method <span style=\"font-family: 'courier new', courier;\">notify<\/span> (line 6) is executed. The\u00a0difference to the first workflow is that the condition <span style=\"font-family: 'courier new', courier;\">waiter != nullptr<\/span> evaluates to <span style=\"font-family: 'courier new', courier;\">true<\/span>. The\u00a0consequence is that the waiter uses the <span style=\"font-family: 'courier new', courier;\">coroutineHandle<\/span> to resume the coroutine.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>If I have one conclusion to this and my last post\u00a0(<a href=\"https:\/\/bit.ly\/InfiniteDataStream\">C++20: An Infinite Data Stream with Coroutines<\/a>), then this one: <strong>Don&#8217;t implement your coroutines<\/strong>. Use existing coroutines such as the one available with\u00a0<a href=\"https:\/\/github.com\/lewissbaker\/cppcoro\">cppcoro<\/a> from Lewis Baker. I strictly follow this advice in my <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-20-coroutines-with-cppcoro\">next post<\/a>.<\/p>\n<h2>Four Voucher for Educative<\/h2>\n<p>There are four vouchers for <a href=\"https:\/\/www.educative.io\/\">educative<\/a> to win: <a href=\"https:\/\/bit.ly\/VoucherEducative\">https:\/\/bit.ly\/VoucherEducative<\/a>. The vouchers allow you to access all <a href=\"https:\/\/www.educative.io\/\">educative.io <\/a>courses for a quarter of a year.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s a typical requirement for thread management to synchronize them. One thread prepares, in this case, a work-package another thread is waiting for.<\/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-5875","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\/5875","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=5875"}],"version-history":[{"count":2,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5875\/revisions"}],"predecessor-version":[{"id":8422,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5875\/revisions\/8422"}],"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=5875"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5875"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5875"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}