{"id":6053,"date":"2020-12-12T15:34:52","date_gmt":"2020-12-12T15:34:52","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/synchronization-with-atomics-in-c-20\/"},"modified":"2023-06-26T09:35:42","modified_gmt":"2023-06-26T09:35:42","slug":"synchronization-with-atomics-in-c-20","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/synchronization-with-atomics-in-c-20\/","title":{"rendered":"Synchronization with Atomics in C++20"},"content":{"rendered":"<p>Sender\/receiver workflows are pretty common for threads. In such a workflow, the receiver is waiting for the sender&#8217;s notification before it continues to work. There are various ways to implement these workflows. With C++11, you can use condition variables or promise\/future pairs; with C++20, you can use atomics.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5945\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/07\/TimelineCpp20CoreLanguage.png\" alt=\"TimelineCpp20CoreLanguage\" width=\"650\" height=\"265\" style=\"display: block; margin-left: auto; margin-right: auto;\" \/><\/p>\n<p>There are various ways to synchronize threads. Each way has its pros and cons. Consequently,&nbsp; I want to compare them. I assume you don&#8217;t know the details of condition variables or promises and futures. Therefore, I will give a short refresher.<\/p>\n<h2>Condition Variables<\/h2>\n<p>A condition variable can fulfill the role of a sender or a receiver. As a sender, it can notify one or more receivers.<\/p>\n<p>&nbsp;<\/p>\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;\">\/\/ threadSynchronisationConditionVariable.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;condition_variable&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;mutex&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;thread&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\r\n\r\nstd<span style=\"color: #555555;\">::<\/span>mutex mutex_;\r\nstd<span style=\"color: #555555;\">::<\/span>condition_variable condVar;\r\n\r\nstd<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> myVec{};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">prepareWork<\/span>() {                                        <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n\r\n    {\r\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_);\r\n        myVec.insert(myVec.end(), {<span style=\"color: #ff6600;\">0<\/span>, <span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">0<\/span>, <span style=\"color: #ff6600;\">3<\/span>});            <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n    }\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Sender: Data prepared.\"<\/span>  <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    condVar.notify_one();\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">completeWork<\/span>() {                                       <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Worker: Waiting for data.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\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_);\r\n    condVar.wait(lck, [] { <span style=\"color: #006699; font-weight: bold;\">return<\/span> not myVec.empty(); });\r\n    myVec[<span style=\"color: #ff6600;\">2<\/span>] <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">2<\/span>;                                           <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Waiter: Complete the work.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\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> myVec) 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>;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t1(prepareWork);\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2(completeWork);\r\n\r\n    t1.join();\r\n    t2.join();\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n  \r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The program has two child threads:<span style=\"font-family: courier new, courier;\"><\/span><code>t1<\/code> and <code>t2<\/code>. They get their payload <code>prepareWork<\/code> and <code>completeWork<\/code>&nbsp;in lines (1) and (2). The function <code>prepareWork<\/code> notifies that it is done with the preparation of the work: <code>condVar.notify_one()<\/code>. While holding the lock, the thread<code> t2<\/code> is waiting for its notification: <code>condVar.wait(lck, []{ return not myVec.empty(); })<\/code>. The waiting thread always performs the same steps. When it is waked up, it checks the predicate while holding the lock (<code>[]{ return not myVec.empty();<\/code>). If the predicate does not hold, it puts itself back to sleep. If the predicate holds,&nbsp; it continues with its work. In the concrete workflow, the sending thread puts the initial values into the <code>std::vector<\/code>(3),&nbsp; which the receiving thread completes (4).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6051\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/threadSynchronisationConditionVariable.png\" alt=\"threadSynchronisationConditionVariable\" width=\"500\" height=\"579\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/threadSynchronisationConditionVariable.png 613w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/threadSynchronisationConditionVariable-259x300.png 259w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p>Condition variables have many inherent issues. For example, the receiver could be awakened without notification or could lose the notification. The first issue is spurious wakeup, and the second is lost wakeup. The predicate protects against both flaws. The notification would be lost when the sender sends its notification before the receiver is in the wait state and does not use a predicate.<br \/>Consequently, the receiver waits for something that never happens. This is a deadlock. When you study the program&#8217;s output, you see that each second run would cause a deadlock if I would not use a predicate. Of course, it is possible to use condition variables without a predicate.<\/p>\n<p>If you want to know the sender\/receiver workflow details and the traps of condition variables, read my previous post, &#8220;<a 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>&#8220;.<\/p>\n<p>When you only need a one-time notification, such as in the previous program, promises and futures are a better choice than condition variables. Promises and futures cannot be victims of spurious or lost wakeups.<\/p>\n<\/p>\n<h2>Promises and Futures<\/h2>\n<p>A promise can send a value, an exception, or a notification to its associated future. Let me use a promise and a future to refactor the previous workflow. Here is the same workflow using a promise\/future pair.<\/p>\n<p>&nbsp;<\/p>\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;\">\/\/ threadSynchronisationPromiseFuture.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;future&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;thread&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\r\n\r\nstd<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> myVec{};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">prepareWork<\/span>(std<span style=\"color: #555555;\">::<\/span>promise<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">void<\/span><span style=\"color: #555555;\">&gt;<\/span> prom) {\r\n\r\n    myVec.insert(myVec.end(), {<span style=\"color: #ff6600;\">0<\/span>, <span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">0<\/span>, <span style=\"color: #ff6600;\">3<\/span>});\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Sender: Data prepared.\"<\/span>  <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    prom.set_value();                                     <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">completeWork<\/span>(std<span style=\"color: #555555;\">::<\/span>future<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">void<\/span><span style=\"color: #555555;\">&gt;<\/span> fut){\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Worker: Waiting for data.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    fut.wait();<span style=\"color: #0099ff; font-style: italic;\">                                           \/\/ (2)<\/span>\r\n    myVec[<span style=\"color: #ff6600;\">2<\/span>] <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">2<\/span>;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Waiter: Complete the work.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\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> myVec) 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>;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>promise<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">void<\/span><span style=\"color: #555555;\">&gt;<\/span> sendNotification;\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> waitForNotification <span style=\"color: #555555;\">=<\/span> sendNotification.get_future();\r\n\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t1(prepareWork, std<span style=\"color: #555555;\">::<\/span>move(sendNotification));\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2(completeWork, std<span style=\"color: #555555;\">::<\/span>move(waitForNotification));\r\n\r\n    t1.join();\r\n    t2.join();\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n  \r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>When you study the workflow, you recognize that the synchronization is reduced to its essential parts: <code>prom.set_value()<\/code> (1)&nbsp; and<code> fut.wait() (2). <\/code>There is neither a need to use locks or mutexes nor is there a need to use a predicate to protect against spurious or lost wakeups. I skip the screenshot to this run because it is essentially the same, such as in the case of the previous run with condition variables.<\/p>\n<p>One downside to using promises and futures is that they can only be used once. Here are my previous posts on <a href=\"https:\/\/www.modernescpp.com\/index.php\/tag\/tasks\">promises and futures<\/a>, often called tasks.<\/p>\n<p>If you want to communicate more than once, use condition variables or atomics.<\/p>\n<h2>std::atomic_flag<\/h2>\n<p><span style=\"font-family: courier new, courier;\">std::atomic_flag<\/span>&nbsp;in C++11 has a simple interface. Its member function <span style=\"font-family: courier new, courier;\">clear<\/span> lets you set its value to <span style=\"font-family: courier new, courier;\">false,<\/span> with <span style=\"font-family: courier new, courier;\">test_and_set<\/span> to <span style=\"font-family: courier new, courier;\">true. <\/span>In case you use <span style=\"font-family: courier new, courier;\">test_and_set<\/span> you get the old value back. <code>ATOMIC_FLAG_INIT<\/code> enables it to initialize the <code>std::atomic_flag<\/code> to <code>false<\/code>. <span style=\"font-family: courier new, courier;\">std::atomic_flag<\/span> has two exciting properties.&nbsp;<\/p>\n<p><strong><span style=\"font-family: courier new, courier;\">std::atomic_flag<\/span><\/strong> is<\/p>\n<ul>\n<li>the only lock-free atomic.<\/li>\n<li>the building block for higher thread abstractions.<\/li>\n<\/ul>\n<p>The remaining more powerful atomics can provide their functionality by using a mutex. That is according to the C++ standard. So these atomics have a member function&nbsp;<span style=\"font-family: courier new, courier;\">is_lock_free<\/span>&nbsp;.On the popular platforms, I always get the answer<code> true<\/code><span style=\"font-family: courier new, courier;\">.<\/span> But you should be aware of that. Here are more details on the capabilities of <a href=\"https:\/\/www.modernescpp.com\/index.php\/the-atomic-flag\"><code>std::atomic_flag<\/code><\/a>&nbsp;C++11.<\/p>\n<p>Now, I jump directly from C++11 to C++20. With C++20,<code> std::atomic_flag<\/code> <code>atomicFlag<\/code> support new member functions:&nbsp;<code>atomicFlag.wait(<\/code>), <code>atomicFlag.notify_one()<\/code>, and <code>atomicFlag.notify_all()<\/code>. The member functions <code>notify_one<\/code>&nbsp;or <code>notify_all<\/code> notify one or all of the waiting atomic flags. <code>atomicFlag.wait(boo)<\/code> needs a boolean <code>boo<\/code>. The call <code>atomicFlag.wait(boo)<\/code> blocks until the subsequent notification or spurious wakeup. It checks then if the value&nbsp;&nbsp;<code>atomicFlag<\/code> is equal to <code>boo<\/code> and unblocks if not. The value <code>boo<\/code> serves as a kind of predicate.<\/p>\n<p>Additionally, to C++11, default construction of a <code>std::atomic_flag<\/code> sets it in its <code>false<\/code> state, and you can ask for the value of the <code>std::atomic flag<\/code> via <code>atomicFlag.test()<\/code>. With this knowledge, it&#8217;s pretty easy to refactor previous programs using a <code>std::atomic_flag<\/code>.<\/p>\n<p>&nbsp;<\/p>\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;\">\/\/ threadSynchronisationAtomicFlag.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;atomic&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;thread&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\r\n\r\nstd<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> myVec{};\r\n\r\nstd<span style=\"color: #555555;\">::<\/span>atomic_flag atomicFlag{};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">prepareWork<\/span>() {\r\n\r\n    myVec.insert(myVec.end(), {<span style=\"color: #ff6600;\">0<\/span>, <span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">0<\/span>, <span style=\"color: #ff6600;\">3<\/span>});\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Sender: Data prepared.\"<\/span>  <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    atomicFlag.test_and_set();                             <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n    atomicFlag.notify_one();   \r\n\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">completeWork<\/span>() {\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Worker: Waiting for data.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    atomicFlag.wait(<span style=\"color: #336666;\">false<\/span>);                                <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n    myVec[<span style=\"color: #ff6600;\">2<\/span>] <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">2<\/span>;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Waiter: Complete the work.\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\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> myVec) 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>;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t1(prepareWork);\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2(completeWork);\r\n\r\n    t1.join();\r\n    t2.join();\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n  \r\n}<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The thread preparing the work (1) sets the <code>atomicFlag<\/code> to <code>true<\/code> and sends the notification. The thread completing the work waits for the notification. It is only unblocked if <code>atomicFlag<\/code> is equal to <code>true<\/code>.<\/p>\n<p>Here are a few runs of the program with the Microsoft Compiler.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6052\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/threadSynchronisationAtomicFlag.png\" alt=\"threadSynchronisationAtomicFlag\" width=\"500\" height=\"549\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/threadSynchronisationAtomicFlag.png 556w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/threadSynchronisationAtomicFlag-273x300.png 273w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p>I&#8217;m not sure if I would use a future\/promise pair or a <code>std::atomic_flag<\/code> for such a simple thread synchronization workflow. Both are thread-safe by design and require no protection mechanism so far. Promise and promise are easier to use but <code>std::atomic_flag<\/code> is probably faster. I&#8217;m sure I would not use a condition variable if possible.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>When you create a more complicated thread synchronization workflow, such as a ping\/pong game, a promise\/future pair is no option. You have to use condition variables or atomics for multiple synchronizations. In my<a href=\"https:\/\/www.modernescpp.com\/index.php\/performancecomparison-of-condition-variables-and-atomics-in-c-20\"> next post<\/a>, I will implement a ping\/pong game using condition variables and a <code>std::atomic_flag<\/code> and measure their performance.<\/p>\n<h2>Short Break<\/h2>\n<p>I take a short Christmas break and publish the following post on the 11.th of January. To learn more about C++20, read my new book at <a href=\"https:\/\/leanpub.com\/c20\">Leanpub to C++20<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sender\/receiver workflows are pretty common for threads. In such a workflow, the receiver is waiting for the sender&#8217;s notification before it continues to work. There are various ways to implement these workflows. With C++11, you can use condition variables or promise\/future pairs; with C++20, you can use atomics.<\/p>\n","protected":false},"author":21,"featured_media":5945,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[434,451,446],"class_list":["post-6053","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-atomics","tag-condition-variables","tag-tasks"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6053","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=6053"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6053\/revisions"}],"predecessor-version":[{"id":6719,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6053\/revisions\/6719"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5945"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=6053"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=6053"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=6053"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}