{"id":6061,"date":"2020-12-19T11:11:55","date_gmt":"2020-12-19T11:11:55","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/performancecomparison-of-condition-variables-and-atomics-in-c-20\/"},"modified":"2023-06-26T09:35:04","modified_gmt":"2023-06-26T09:35:04","slug":"performancecomparison-of-condition-variables-and-atomics-in-c-20","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/performancecomparison-of-condition-variables-and-atomics-in-c-20\/","title":{"rendered":"Performance Comparison of Condition Variables and Atomics in C++20"},"content":{"rendered":"<p>After the introduction to <code>std::atomic_flag<\/code> in my last post, <a href=\"https:\/\/bit.ly\/3nF8r3f\">Synchronization with Atomics in C++20<\/a>, I want to dive deeper. Today, I created a ping-pong game using condition variables,<code> std::atomic_flag<\/code> and <code>std::atomic&lt;bool&gt;<\/code>. Let&#8217;s play.<\/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>The key question I want to answer in this post is: What is the fastest way to synchronize threads in C++20? I use in this post three different data types: <code>std::condition_variable<\/code>, <code>std::atomic_flag<\/code>, and <code>std::atomic&lt;bool&gt;<\/code>.<\/p>\n<p>To get comparable numbers, I implement a ping-pong game. One thread executes a <code>ping<\/code> function, and the other thread a <code>pong<\/code> function. For simplicity reasons, I call the thread executing the <code>ping<\/code> function the ping thread and the other thread the pong thread. The ping thread waits for the notification of the pong threads and returns the notification to the pong thread. The game stops after 1,000,000 ball changes. I perform each game five times to get comparable performance numbers.<\/p>\n<p>I made my performance test with the brand new Visual Studio compiler because it already supports synchronization with atomics. Additionally, I compiled the examples with maximum optimization (<code>\/Ox<\/code>).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6055\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/windowsCompiler.png\" alt=\"windowsCompiler\" width=\"500\" height=\"139\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/windowsCompiler.png 674w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/windowsCompiler-300x83.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p>Let me start with C++11.<\/p>\n<\/p>\n<h2>Condition Variables<\/h2>\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;\">\/\/ pingPongConditionVariable.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;condition_variable&gt;<\/span>\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\r\n<span style=\"color: #007788; font-weight: bold;\">bool<\/span> dataReady{<span style=\"color: #336666;\">false<\/span>};\r\n\r\nstd<span style=\"color: #555555;\">::<\/span>mutex mutex_;\r\nstd<span style=\"color: #555555;\">::<\/span>condition_variable condVar1;          <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\nstd<span style=\"color: #555555;\">::<\/span>condition_variable condVar2;         <span style=\"color: #0099ff; font-style: italic;\"> \/\/ (2)<\/span>\r\n\r\nstd<span style=\"color: #555555;\">::<\/span>atomic<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> counter{};\r\nconstexpr <span style=\"color: #007788; font-weight: bold;\">int<\/span> countlimit <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">1<\/span><span style=\"color: #aa0000; background-color: #ffaaaa;\">'<\/span><span style=\"color: #ff6600;\">000<\/span><span style=\"color: #aa0000; background-color: #ffaaaa;\">'<\/span><span style=\"color: #ff6600;\">000<\/span>;\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">ping<\/span>() {\r\n\r\n    <span style=\"color: #006699; font-weight: bold;\">while<\/span>(counter <span style=\"color: #555555;\">&lt;=<\/span> countlimit) {\r\n        {\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            condVar1.wait(lck, []{<span style=\"color: #006699; font-weight: bold;\">return<\/span> dataReady <span style=\"color: #555555;\">==<\/span> <span style=\"color: #336666;\">false<\/span>;});\r\n            dataReady <span style=\"color: #555555;\">=<\/span> <span style=\"color: #336666;\">true<\/span>;\r\n        }\r\n        <span style=\"color: #555555;\">++<\/span>counter;                         <span style=\"color: #0099ff; font-style: italic;\"> <\/span>\r\n        condVar2.notify_one();              <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n  }\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">pong<\/span>() {\r\n\r\n    <span style=\"color: #006699; font-weight: bold;\">while<\/span>(counter <span style=\"color: #555555;\">&lt;<\/span> countlimit) {  \r\n        {\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            condVar2.wait(lck, []{<span style=\"color: #006699; font-weight: bold;\">return<\/span> dataReady <span style=\"color: #555555;\">==<\/span> <span style=\"color: #336666;\">true<\/span>;});\r\n            dataReady <span style=\"color: #555555;\">=<\/span> <span style=\"color: #336666;\">false<\/span>;\r\n        }\r\n        condVar1.notify_one();           <span style=\"color: #0099ff; font-style: italic;\"> \/\/ (3)<\/span>\r\n  }\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    <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>system_clock<span style=\"color: #555555;\">::<\/span>now();  \r\n\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t1(ping);\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2(pong);\r\n\r\n    t1.join();\r\n    t2.join();\r\n  \r\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> dur <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>system_clock<span style=\"color: #555555;\">::<\/span>now() <span style=\"color: #555555;\">-<\/span> start;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Duration: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> dur.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;\r\n\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>I use two condition variables in the program: <code>condVar1<\/code> and <code>condVar2 <\/code>(lines 1 and 2). The ping thread waits for the notification of <code>condVar1<\/code> and sends its notification with <code>condVar2<\/code>. <code>dataReady<\/code> protects against spurious and lost wakeups (see &#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;). The ping-pong game ends when <code>counter<\/code> reaches the <code>countlimit<\/code>. The <code>nofication_one<\/code> calls (lines 3) and the counter are thread-safe and are, therefore, outside the critical region.<\/p>\n<p>Here are the numbers:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6056\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongConditionVariable.png\" alt=\"pingPongConditionVariable\" width=\"400\" height=\"294\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongConditionVariable.png 1028w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongConditionVariable-300x221.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongConditionVariable-1024x753.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongConditionVariable-768x565.png 768w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/p>\n<p>The average execution time is 0.52 seconds.<\/p>\n<p>Porting this play to <code>std::atomic_flags<\/code>&#8216;s in C++20 is straightforward.<\/p>\n<h2><code>std::atomic_flag<\/code><\/h2>\n<p>Here is the play using two atomic flags.<\/p>\n<h3>Two Atomic Flags<\/h3>\n<p>In the following program, I replace the waiting on the condition variable with the waiting on the atomic flag and the notification of the condition variable with the setting of the atomic flag followed by the notification.<\/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;\">\/\/ pingPongAtomicFlags.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\r\nstd<span style=\"color: #555555;\">::<\/span>atomic_flag condAtomicFlag1{};\r\nstd<span style=\"color: #555555;\">::<\/span>atomic_flag condAtomicFlag2{};\r\n\r\nstd<span style=\"color: #555555;\">::<\/span>atomic<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> counter{};\r\nconstexpr <span style=\"color: #007788; font-weight: bold;\">int<\/span> countlimit <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">1<\/span><span style=\"color: #aa0000; background-color: #ffaaaa;\">'<\/span><span style=\"color: #ff6600;\">000<\/span><span style=\"color: #aa0000; background-color: #ffaaaa;\">'<\/span><span style=\"color: #ff6600;\">000<\/span>;\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">ping<\/span>() {\r\n    <span style=\"color: #006699; font-weight: bold;\">while<\/span>(counter <span style=\"color: #555555;\">&lt;=<\/span> countlimit) {\r\n        condAtomicFlag1.wait(<span style=\"color: #336666;\">false<\/span>);               <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n        condAtomicFlag1.clear();                   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n\r\n        <span style=\"color: #555555;\">++<\/span>counter;\r\n        \r\n        condAtomicFlag2.test_and_set();           <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n        condAtomicFlag2.notify_one();             <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n    }\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">pong<\/span>() {\r\n    <span style=\"color: #006699; font-weight: bold;\">while<\/span>(counter <span style=\"color: #555555;\">&lt;<\/span> countlimit) {\r\n        condAtomicFlag2.wait(<span style=\"color: #336666;\">false<\/span>);\r\n        condAtomicFlag2.clear();\r\n        \r\n        condAtomicFlag1.test_and_set();\r\n        condAtomicFlag1.notify_one();\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     <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>system_clock<span style=\"color: #555555;\">::<\/span>now();  \r\n\r\n    condAtomicFlag1.test_and_set();                    <span style=\"color: #0099ff; font-style: italic;\">\/\/ (5)<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t1(ping);\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2(pong);\r\n\r\n    t1.join();\r\n    t2.join();\r\n\r\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> dur <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>system_clock<span style=\"color: #555555;\">::<\/span>now() <span style=\"color: #555555;\">-<\/span> start;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Duration: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> dur.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;\r\n\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>A call <code>condAtomicFlag1.wait(false)<\/code> (1) blocks, if the value of the atomic flag is <code>false<\/code>. On the contrary, it returns if <code>condAtomicFlag1<\/code> has the value <code>true<\/code>. The boolean value serves as a kind of predicate and must, therefore, be set back to <code>false<\/code> (2). Before the notification (3) is sent to the pong thread,&nbsp;<code>condAtomicFlag1<\/code> is set to <code>true <\/code>(4). The initial setting of<code> condAtomicFlag1<\/code> to <code>true<\/code> (5) starts the game. <span style=\"color: #0099ff; font-style: italic;\"><\/span><\/p>\n<p>Thanks to <code>std::atomic_flag<\/code> the game end earlier.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6057\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicFlags.png\" alt=\"pingPongAtomicFlags\" width=\"400\" height=\"310\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicFlags.png 972w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicFlags-300x232.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicFlags-768x594.png 768w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/p>\n<p>On average, a game takes 0.32 seconds.<\/p>\n<p>When you analyze the program, you may recognize that one atomics flag is sufficient for the play.<\/p>\n<h3>One Atomic Flag<\/h3>\n<p>Using one atomic flag makes the play easier to understand.<\/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;\">\/\/ pingPongAtomicFlag.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\r\nstd<span style=\"color: #555555;\">::<\/span>atomic_flag condAtomicFlag{};\r\n\r\nstd<span style=\"color: #555555;\">::<\/span>atomic<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> counter{};\r\nconstexpr <span style=\"color: #007788; font-weight: bold;\">int<\/span> countlimit <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">1<\/span><span style=\"color: #aa0000; background-color: #ffaaaa;\">'<\/span><span style=\"color: #ff6600;\">000<\/span><span style=\"color: #aa0000; background-color: #ffaaaa;\">'<\/span><span style=\"color: #ff6600;\">000<\/span>;\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">ping<\/span>() {\r\n    <span style=\"color: #006699; font-weight: bold;\">while<\/span>(counter <span style=\"color: #555555;\">&lt;=<\/span> countlimit) {\r\n        condAtomicFlag.wait(<span style=\"color: #336666;\">true<\/span>);\r\n        condAtomicFlag.test_and_set();\r\n        \r\n        <span style=\"color: #555555;\">++<\/span>counter;\r\n        \r\n        condAtomicFlag.notify_one();\r\n    }\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">pong<\/span>() {\r\n    <span style=\"color: #006699; font-weight: bold;\">while<\/span>(counter <span style=\"color: #555555;\">&lt;<\/span> countlimit) {\r\n        condAtomicFlag.wait(<span style=\"color: #336666;\">false<\/span>);\r\n        condAtomicFlag.clear();\r\n        condAtomicFlag.notify_one();\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     <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>system_clock<span style=\"color: #555555;\">::<\/span>now();  \r\n\r\n    \r\n    condAtomicFlag.test_and_set();\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t1(ping);\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2(pong);\r\n\r\n    t1.join();\r\n    t2.join();\r\n\r\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> dur <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>system_clock<span style=\"color: #555555;\">::<\/span>now() <span style=\"color: #555555;\">-<\/span> start;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Duration: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> dur.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;\r\n\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>In this case, the ping thread blocks on <code>true<\/code> but the pong thread blocks on <code>false<\/code>. Using one or two atomic flags make no difference from the performance perspective.<\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6058\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicFlag.png\" alt=\"pingPongAtomicFlag\" width=\"400\" height=\"309\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicFlag.png 972w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicFlag-300x232.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicFlag-768x594.png 768w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/p>\n<p>The average execution time is 0.31 seconds.<\/p>\n<p>&nbsp;I used in this example <code>std::atomic_flag<\/code> such as an atomic boolean. Let&#8217;s give it another try with<code> std::atomic&lt;bool&gt;<\/code>.<\/p>\n<h2><code>std::atomic&lt;bool&gt;<\/code><\/h2>\n<p>From the readability perspective, I prefer the following C++20 implementation based on <code>std::atomic&lt;bool&gt;.<\/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;\">\/\/ pingPongAtomicBool.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\r\nstd<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> atomicBool{};\r\n\r\nstd<span style=\"color: #555555;\">::<\/span>atomic<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> counter{};\r\nconstexpr <span style=\"color: #007788; font-weight: bold;\">int<\/span> countlimit <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">1<\/span><span style=\"color: #aa0000; background-color: #ffaaaa;\">'<\/span><span style=\"color: #ff6600;\">000<\/span><span style=\"color: #aa0000; background-color: #ffaaaa;\">'<\/span><span style=\"color: #ff6600;\">000<\/span>;\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">ping<\/span>() {\r\n    <span style=\"color: #006699; font-weight: bold;\">while<\/span>(counter <span style=\"color: #555555;\">&lt;=<\/span> countlimit) {\r\n        atomicBool.wait(<span style=\"color: #336666;\">true<\/span>);\r\n        atomicBool.store(<span style=\"color: #336666;\">true<\/span>);\r\n\r\n        <span style=\"color: #555555;\">++<\/span>counter;\r\n        \r\n        atomicBool.notify_one();\r\n    }\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">pong<\/span>() {\r\n    <span style=\"color: #006699; font-weight: bold;\">while<\/span>(counter <span style=\"color: #555555;\">&lt;<\/span> countlimit) {\r\n        atomicBool.wait(<span style=\"color: #336666;\">false<\/span>);\r\n        atomicBool.store(<span style=\"color: #336666;\">false<\/span>);\r\n        atomicBool.notify_one();\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>boolalpha <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"atomicBool.is_lock_free(): \"<\/span>              <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n              <span style=\"color: #555555;\">&lt;&lt;<\/span> atomicBool.is_lock_free()  <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl; \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    <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>system_clock<span style=\"color: #555555;\">::<\/span>now();\r\n\r\n    atomicBool.store(<span style=\"color: #336666;\">true<\/span>);\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t1(ping);\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2(pong);\r\n\r\n    t1.join();\r\n    t2.join();\r\n\r\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> dur <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>system_clock<span style=\"color: #555555;\">::<\/span>now() <span style=\"color: #555555;\">-<\/span> start;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Duration: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> dur.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;\r\n\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p><code>std::atomic&lt;bool&gt;<\/code> can internally use a locking mechanism such as a mutex. As I assumed, my Windows runtime is lock-free (1).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6059\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicBool.png\" alt=\"pingPongAtomicBool\" width=\"400\" height=\"539\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicBool.png 999w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicBool-223x300.png 223w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicBool-761x1024.png 761w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/pingPongAtomicBool-768x1034.png 768w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/p>\n<p>On average, the execution time is 0.38 seconds.<\/p>\n<h2>All Numbers<\/h2>\n<p>As expected, condition variables are the slowest way, and atomic flag is the fastest way to synchronize threads. The performance of a<code> std::atomic&lt;bool&gt;<\/code> is in-between.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6060\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/PerformanceComparison.png\" alt=\"PerformanceComparison\" width=\"500\" height=\"51\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/PerformanceComparison.png 879w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/PerformanceComparison-300x31.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/12\/PerformanceComparison-768x79.png 768w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>With C++20, we have a few new mechanisms for thread coordination. In my<a href=\"https:\/\/www.modernescpp.com\/index.php\/semaphores-in-c-20\"> next post<\/a>, I will look deeper into latches, barriers, and semaphores. They also allow it to play Ping-Pong.<\/p>\n<p>&nbsp;<\/p>\n<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<div id=\"simple-translate\">&nbsp;<\/div>\n","protected":false},"excerpt":{"rendered":"<p>After the introduction to std::atomic_flag in my last post, Synchronization with Atomics in C++20, I want to dive deeper. Today, I created a ping-pong game using condition variables, std::atomic_flag and std::atomic&lt;bool&gt;. Let&#8217;s play.<\/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],"class_list":["post-6061","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-atomics","tag-condition-variables"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6061","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=6061"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6061\/revisions"}],"predecessor-version":[{"id":6718,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6061\/revisions\/6718"}],"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=6061"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=6061"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=6061"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}