{"id":5449,"date":"2018-06-01T04:21:31","date_gmt":"2018-06-01T04:21:31","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-be-aware-of-the-traps-of-condition-variables\/"},"modified":"2023-06-26T11:50:19","modified_gmt":"2023-06-26T11:50:19","slug":"c-core-guidelines-be-aware-of-the-traps-of-condition-variables","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-be-aware-of-the-traps-of-condition-variables\/","title":{"rendered":"C++ Core Guidelines: Be Aware of the Traps of Condition Variables"},"content":{"rendered":"<p>Today, I am writing a scary post about condition variables. You should be aware of these issues of condition variables. The C++ core guideline CP 42 states: &#8220;Don&#8217;t wait without a condition&#8221;.<\/p>\n<p><!--more--><\/p>\n<h5 id=\"reason-285\" style=\"margin-bottom: 0.5rem; font-weight: bold; line-height: 1.25; color: #313131; margin-top: 1rem; font-size: 1rem; display: inline; font-family: 'PT Sans', Helvetica, Arial, sans-serif; font-style: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; background-color: #ffffff;\">&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5448\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/06\/trapMice.jpg\" alt=\"trapMice\" width=\"700\" height=\"497\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/06\/trapMice.jpg 1280w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/06\/trapMice-300x213.jpg 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/06\/trapMice-1024x726.jpg 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/06\/trapMice-768x545.jpg 768w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/h5>\n<p>&nbsp;<\/p>\n<p>Wait! Condition variables support a pretty simple concept. One thread prepares something and sends a notification another thread is waiting for. Why can&#8217;t this be so dangerous? Okay, let&#8217;s start with the only rule for today.<\/p>\n<h2><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconc-wait\" style=\"color: #268bd2; text-decoration: none;\">CP.42: Don\u2019t <code class=\"highlighter-rouge no-highlight\" style=\"font-family: 'Roboto Mono', monospace; padding: 0.2em; font-size: 18px; background-color: #f9f9f9;\"><\/code>wait without a condition<\/a><\/h2>\n<p>Here is the rationale for the rule: &#8220;A&nbsp;wait&nbsp;without a condition can miss a wakeup or wake up simply to find that there is no work to do.&#8221; What does that mean? Condition variables can be victims of two severe issues: lost wakeup and spurious wakeup. The key concern about condition variables is that they have no memory.<\/p>\n<p>Before I present this issue, let me first do it right. Here is the pattern of how to use condition variables.<\/p>\n<p>&nbsp;<\/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>\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;thread&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\n<span style=\"color: #007788; font-weight: bold;\">bool<\/span> dataReady{<span style=\"color: #336666;\">false<\/span>};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">waitingForWork<\/span>(){\r\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;\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> dataReady; });   <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;\">\"Running \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">setDataReady<\/span>(){\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        dataReady <span style=\"color: #555555;\">=<\/span> <span style=\"color: #336666;\">true<\/span>;\r\n    }\r\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;\r\n    condVar.notify_one();                        <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\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(waitingForWork);               <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\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>\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>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;\">&nbsp;waitingForWork<\/span>&nbsp;and <span style=\"font-family: 'courier new', courier;\">setDataRead<\/span>&nbsp;in lines (1 and 2). <span style=\"font-family: 'courier new', courier;\">setDataReady<\/span>&nbsp;notifies &#8211; using the condition variable <span style=\"font-family: 'courier new', courier;\">condVar<\/span>&nbsp;&#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>&nbsp;waits 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>&nbsp;is sufficient because it calls to lock and unlock only once. In the case of the receiver, a <span style=\"font-family: 'courier new', courier;\">std::unique_lock<\/span>&nbsp;is necessary because it usually frequently locks and unlocks its mutex.<\/p>\n<p>Here is the output of the program.<\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" alignleft size-full wp-image-4756\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/05\/conditionVariable.png\" alt=\"conditionVariable\" width=\"400\" height=\"197\" style=\"float: left;\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/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>&nbsp;without a predicate. This workflow seems quite too complicated for such a simple synchronization of threads.&nbsp;<\/p>\n<p>Now we are back to the missing memory and the two phenomena called lost wakeup and spurious wakeup.<\/p>\n<\/p>\n<h3>Lost Wakeup and Spurious Wakeup<\/h3>\n<ul>\n<li><strong>Lost wakeup<\/strong>:&nbsp;The phenomenon of the lost wakeup is that the sender sends its notification before the receiver gets to its wait state. The consequence is that the notification is lost. The C++ standard describes condition variables as a simultaneous synchronization mechanism: &#8220;The condition_variable class is a synchronization primitive that can be used to block a thread, or multiple threads <strong>at the same time<\/strong>, &#8230;&#8221;. So the notification gets lost. The receiver is waiting and waiting and&#8230;<\/li>\n<li><strong>Spurious wakeup<\/strong>: The receiver may wake up although no notification has happened. At a minimum <a href=\"https:\/\/en.wikipedia.org\/wiki\/POSIX_Threads\">POSIX Threads<\/a>&nbsp;and the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Windows_API\">Windows AP<\/a>I can be victims of these phenomena.<\/li>\n<\/ul>\n<p>To become not the victim of these two issues, you have to use an additional predicate as memory or, as a rule, state it as an additional condition. If you don&#8217;t believe it, here is the wait workflow.<\/p>\n<h3>The wait workflow&nbsp;<\/h3>\n<p>In the initial wait processing, the thread locks the mutex and then checks the predicate <span style=\"font-family: 'courier new', courier;\">[]{ return dataReady; }<\/span>.<\/p>\n<ul>\n<li>If the call of the predicated evaluates to\n<ul>\n<li><span style=\"font-family: 'courier new', courier;\">true<\/span>: the thread continues its work.<\/li>\n<li><span style=\"font-family: 'courier new', courier;\">false<\/span>: <span style=\"font-family: 'courier new', courier;\">condVar.wait()<\/span>&nbsp;unlocks the mutex and puts the thread in a waiting (blocking) state<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>If the condition_variable <span style=\"font-family: 'courier new', courier;\">condVar<\/span> is in the waiting state and gets a notification or a spurious wakeup, the following steps happen.<\/p>\n<ul>\n<li>The thread is unblocked, and will reacquire the lock on the mutex.&nbsp;<\/li>\n<li>The thread checks the predicate.<\/li>\n<li>If the call of the predicated evaluates to\n<ul>\n<li><span style=\"font-family: 'courier new', courier;\">true<\/span>: the thread continues its work.<\/li>\n<li><span style=\"font-family: 'courier new', courier;\">false<\/span>: <span style=\"font-family: 'courier new', courier;\">condVar.wait<\/span>() unlocks the mutex and puts the thread in a waiting (blocking) state.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Complicated! Right? Don&#8217;t you believe me?<\/p>\n<h3>Without a predicate<\/h3>\n<p>What will happen if I remove the predicate from the last example?&nbsp;&nbsp;<\/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;\">\/\/ conditionVariableWithoutPredicate.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;thread&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\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">waitingForWork<\/span>(){\r\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;\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: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\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;\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">setDataReady<\/span>(){\r\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;\r\n    condVar.notify_one();                   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\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(waitingForWork);\r\n  std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2(setDataReady);\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>Now, the wait call in line (1) does not use a predicate, and the synchronization looks relatively easy. Sad to say, but the program now has a race condition which you can see in the very first execution. The screenshot shows the deadlock.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-4757\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/05\/conditionVariableWithoutPredicate.png\" alt=\"conditionVariableWithoutPredicate\" width=\"500\" height=\"178\" style=\"display: block; margin-left: auto; margin-right: auto;\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>The sender sends in line (1)&nbsp;&nbsp;(<span style=\"font-family: 'courier new', courier;\">condVar.notify_one()<\/span>) its notification before the receiver is capable of receiving it; therefore, the receiver will sleep forever.&nbsp;<\/p>\n<p>Okay, lesson learned the hard way. The predicate is necessary, but there must be a way to simplify the program <span style=\"font-family: courier new, courier;\">conditionVariables.cpp<\/span>?<\/p>\n<h3>An atomic predicate&nbsp;<\/h3>\n<p>Maybe, you saw it. The variable <span style=\"font-family: Courier New, Courier, monospace;\">dataReady<\/span> is just a boolean. We should make it an atomic boolean and, therefore, eliminate the mutex on the sender.<\/p>\n<p>Here we are:<\/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;\">\/\/ conditionVariableAtomic.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;atomic&gt;<\/span>\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;thread&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>atomic<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">bool<\/span><span style=\"color: #555555;\">&gt;<\/span> dataReady{<span style=\"color: #336666;\">false<\/span>};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">waitingForWork<\/span>(){\r\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;\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> dataReady.load(); });   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\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;\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">setDataReady<\/span>(){\r\n    dataReady <span style=\"color: #555555;\">=<\/span> <span style=\"color: #336666;\">true<\/span>;\r\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;\r\n    condVar.notify_one();\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(waitingForWork);\r\n  std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2(setDataReady);\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 is relatively straightforward compared to the first version because <span style=\"font-family: Courier New, Courier, monospace;\">dataReady <\/span>has not to&nbsp;be&nbsp;protected by a mutex. Once more, the program has a race condition that can cause a deadlock. Why? <span style=\"font-family: Courier New, Courier, monospace;\">dataReady <\/span>is atomic! Right, but the wait expression (<span style=\"font-family: Courier New, Courier, monospace;\">condVar.wait(lck, []{ return dataReady.load(); });<\/span>) in line (1) is way more complicated than it seems.<\/p>\n<p>The wait expression is equivalent to the following four lines:<\/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%;\">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_);<br \/><span style=\"color: #006699; font-weight: bold;\">while<\/span> ( <span style=\"color: #555555;\">!<\/span>[]{ <span style=\"color: #006699; font-weight: bold;\">return<\/span> dataReady.load(); }() {\r\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ time window (1)<\/span>\r\n    condVar.wait(lck);\r\n}\r\n<\/pre>\n<\/div>\n<p>Even if you make<span style=\"font-family: Courier New, Courier, monospace;\"> dataReady<\/span> an atomic, it must be modified under the mutex; if not, the modification to the waiting thread may be published but not correctly synchronized. This race condition may cause a deadlock. What does that mean: published but not correctly synchronized? Let&#8217;s look closer at the previous code snippet and assume that data is atomic and is not protected by the mutex <span style=\"font-family: Courier New, Courier, monospace;\">mutex<\/span>.<\/p>\n<p>Let me assume the notification is sent while the condition variable <span style=\"font-family: Courier New, Courier, monospace;\">condVar<\/span> is in the wait expression but not the waiting state. This means the execution of the thread is in the source snippet, in line with the comment time window ( line 1). The result is that the notification is lost. Afterward, the thread returns to the waiting state and presumably sleeps forever.&nbsp;<\/p>\n<p>This wouldn&#8217;t have happened if <span style=\"font-family: Courier New, Courier, monospace;\">dataReady <\/span>had been protected by a mutex. Because of the synchronization with the mutex, the notification would only be sent if the condition variable and, therefore, the receiver thread is in the waiting state.&nbsp;<\/p>\n<p>What a scary story! Is there no possibility of making the initial program <span style=\"font-family: 'courier new', courier;\">conditionVariables.cpp<\/span> more straightforward? No, not with a condition variable, but you can use a promise and future pair to complete the job. For the details, read the post <a href=\"https:\/\/www.modernescpp.com\/index.php\/thread-synchronization-with-condition-variables-or-tasks\">Thread Synchronisation with Condition Variables or Tasks<\/a>.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>Now, I&#8217;m nearly done with the rules of concurrency. The rules for parallelism, message passing, and vectorization have no content; therefore, I will skip them and write in my <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-concurrency-and-lock-free-programming\">next post<\/a> mainly about lock-free programming.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today, I am writing a scary post about condition variables. You should be aware of these issues of condition variables. The C++ core guideline CP 42 states: &#8220;Don&#8217;t wait without a condition&#8221;.<\/p>\n","protected":false},"author":21,"featured_media":5448,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[372],"tags":[451],"class_list":["post-5449","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-modern-c","tag-condition-variables"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5449","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=5449"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5449\/revisions"}],"predecessor-version":[{"id":6825,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5449\/revisions\/6825"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5448"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5449"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5449"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5449"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}