{"id":4748,"date":"2016-05-12T20:29:00","date_gmt":"2016-05-12T20:29:00","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/prefer-locks-to-mutexes\/"},"modified":"2023-08-15T11:34:23","modified_gmt":"2023-08-15T11:34:23","slug":"prefer-locks-to-mutexes","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/prefer-locks-to-mutexes\/","title":{"rendered":"Prefer Locks to Mutexes"},"content":{"rendered":"<p>If the<a href=\"https:\/\/www.modernescpp.com\/index.php\/the-risk-of-mutexes\"> previous post <\/a>showed something, it&#8217;s that you should use mutexes with great care. That&#8217;s why you should wrap them in a lock.<\/p>\n<p><!--more--><\/p>\n<h2>Locks<\/h2>\n<p>Locks take care of their resource following the <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/language\/raii\">RAII<\/a> idiom. &nbsp;A lock automatically binds its mutex in the constructor and releases it in the destructor. This considerably reduces the risk of a deadlock because the runtime takes care of the mutex.<\/p>\n<p>Locks are available in two flavors in C++11. <span style=\"font-family: courier new,courier;\">std::lock_guard<\/span> for the simple, &nbsp;and&nbsp;<span style=\"font-family: courier new,courier;\">std::unique-lock<\/span> for the advanced use case.<\/p>\n<h3><span style=\"font-family: courier new,courier;\"><a id=\"lock_guard\">std::lock_guard<\/a><\/span><\/h3>\n<p>First is the simple use case.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff none repeat scroll 0% 0%; overflow: auto; width: auto; border-width: 0.1em 0.1em 0.1em 0.8em;\">\n<pre style=\"margin: 0px; line-height: 125%;\">mutex m;\nm.lock();\nsharedVariable= getVar();\nm.unlock();\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>With so little code, mutex <span style=\"font-family: courier new,courier;\">m<\/span> ensures access to the critical section&nbsp;<span style=\"font-family: courier new,courier;\">sharedVariable= getVar()<\/span> is sequential. Sequential means &nbsp;&#8211; in this particular case &#8211; &nbsp;that each thread gains access to the critical section in order. The code is simple but prone to deadlocks. Deadlock appears if the critical section throws an exception or the programmer forgets to unlock the mutex. With <span style=\"font-family: courier new,courier;\">std::lock_guard<\/span> we can do this more elegant:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff none repeat scroll 0% 0%; overflow: auto; width: auto; border-width: 0.1em 0.1em 0.1em 0.8em;\">\n<pre style=\"margin: 0px; line-height: 125%;\">{\n  std::mutex m,\n  std::lock_guard&lt;std::mutex&gt; lockGuard(m);\n  sharedVariable= getVar();\n}\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>That was easy. But what about the opening and closing brackets? The lifetime of <span style=\"font-family: courier new,courier;\">std::lock_guard<\/span> is limited by the brackets (<a href=\"http:\/\/en.cppreference.com\/w\/cpp\/language\/scope#Block_scope\">http:\/\/en.cppreference.com\/w\/cpp\/language\/scope#Block_scope<\/a>). That means its lifetime ends when it leaves the critical section. At that time, the destructor of<span style=\"font-family: courier new,courier;\"> std::lock_guard i<\/span>s called, and &#8211; I guess you know it &#8211; the mutex is released. It happens automatically, and, in addition, it happens if <span style=\"font-family: 'courier new', courier;\">getVar()<\/span> in&nbsp;<span style=\"font-family: courier new,courier;\">sharedVariable = getVar()<\/span> throws an exception. Of course, function body scope or loop scope also limits the lifetime of an object.<\/p>\n<h3><span style=\"font-family: courier new,courier;\"><a id=\"unique_lock\">std::unique_lock<\/a><\/span><\/h3>\n<p>std::unique_lock is mightier but more expansive than its small brother&nbsp;<span style=\"font-family: courier new,courier;\">std::lock_guard<\/span>.<\/p>\n<p>A <span style=\"font-family: courier new,courier;\">std::unique_lock <\/span>enables you<span style=\"font-family: courier new,courier;\"><\/span>in addition to <span style=\"font-family: courier new,courier;\">std::lock_guard <\/span><\/p>\n<ul>\n<li>create it without an associated mutex<\/li>\n<li>create it without a locked associated mutex<\/li>\n<li>explicitly and repeatedly set or release the lock of the associated mutex<\/li>\n<li>move the mutex<\/li>\n<li>try to lock the mutex<\/li>\n<li>delayed lock the associated mutex<\/li>\n<\/ul>\n<p>But why is it necessary? Remember the deadlock from the post <a href=\"https:\/\/www.modernescpp.com\/index.php?option=com_content&amp;view=article&amp;id=71;gefahren-von-mutexen&amp;catid=35;c&amp;Itemid=101#DeadlockVerschiedeneReihenfolge\">Risks of mutexes<\/a>? The reason for the deadlock was the mutexes were locked in a different sequence.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff none repeat scroll 0% 0%; overflow: auto; width: auto; border-width: 0.1em 0.1em 0.1em 0.8em;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0px; line-height: 125%;\"> 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0px; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ deadlock.cpp<\/span>\n\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #0000ff;\">#include &lt;chrono&gt;<\/span>\n<span style=\"color: #0000ff;\">#include &lt;mutex&gt;<\/span>\n<span style=\"color: #0000ff;\">#include &lt;thread&gt;<\/span>\n\n<span style=\"color: #0000ff;\">struct<\/span> CriticalData{\n  std::mutex mut;\n};\n\n<span style=\"color: #2b91af;\">void<\/span> deadLock(CriticalData&amp; a, CriticalData&amp; b){\n\n  a.mut.lock();\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"get the first mutex\"<\/span> &lt;&lt; std::endl;\n  std::this_thread::sleep_for(std::chrono::milliseconds(1));\n  b.mut.lock();\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"get the second mutex\"<\/span> &lt;&lt; std::endl;\n  <span style=\"color: #008000;\">\/\/ do something with a and b<\/span>\n  a.mut.unlock();\n  b.mut.unlock();\n  \n}\n\n<span style=\"color: #2b91af;\">int<\/span> main(){\n\n  CriticalData c1;\n  CriticalData c2;\n\n  std::<span style=\"color: #0000ff;\">thread<\/span> t1([&amp;]{deadLock(c1,c2);});\n  std::<span style=\"color: #0000ff;\">thread<\/span> t2([&amp;]{deadLock(c2,c1);});\n\n  t1.join();\n  t2.join();\n\n}\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The solution is easy. The function deadlock has to lock their mutex in an atomic fashion. That&#8217;s precisely what happens in the following example.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff none repeat scroll 0% 0%; overflow: auto; width: auto; border-width: 0.1em 0.1em 0.1em 0.8em;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0px; line-height: 125%;\"> 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0px; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ deadlockResolved.cpp<\/span>\n\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #0000ff;\">#include &lt;chrono&gt;<\/span>\n<span style=\"color: #0000ff;\">#include &lt;mutex&gt;<\/span>\n<span style=\"color: #0000ff;\">#include &lt;thread&gt;<\/span>\n\n<span style=\"color: #0000ff;\">struct<\/span> CriticalData{\n  std::mutex mut;\n};\n\n<span style=\"color: #2b91af;\">void<\/span> deadLock(CriticalData&amp; a, CriticalData&amp; b){\n\n  std::unique_lock&lt;std::mutex&gt;guard1(a.mut,std::defer_lock);\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"Thread: \"<\/span> &lt;&lt; std::this_thread::get_id() &lt;&lt; <span style=\"color: #a31515;\">\" first mutex\"<\/span> &lt;&lt;  std::endl;\n\n  std::this_thread::sleep_for(std::chrono::milliseconds(1));\n\n  std::unique_lock&lt;std::mutex&gt;guard2(b.mut,std::defer_lock);\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"    Thread: \"<\/span> &lt;&lt; std::this_thread::get_id() &lt;&lt; <span style=\"color: #a31515;\">\" second mutex\"<\/span> &lt;&lt;  std::endl;\n\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"        Thread: \"<\/span> &lt;&lt; std::this_thread::get_id() &lt;&lt; <span style=\"color: #a31515;\">\" get both mutex\"<\/span> &lt;&lt; std::endl;\n  std::lock(guard1,guard2);\n  <span style=\"color: #008000;\">\/\/ do something with a and b<\/span>\n}\n\n<span style=\"color: #2b91af;\">int<\/span> main(){\n\n  std::cout &lt;&lt; std::endl;\n\n  CriticalData c1;\n  CriticalData c2;\n\n  std::<span style=\"color: #0000ff;\">thread<\/span> t1([&amp;]{deadLock(c1,c2);});\n  std::<span style=\"color: #0000ff;\">thread<\/span> t2([&amp;]{deadLock(c2,c1);});\n\n  t1.join();\n  t2.join();\n\n  std::cout &lt;&lt; std::endl;\n\n}\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>If you call the constructor of <span style=\"font-family: courier new,courier;\">std::unique_lock<\/span> with the argument <span style=\"font-family: courier new,courier;\">std::defer_lock<span style=\"font-family: arial,helvetica,sans-serif;\">, the lock will not be locked <span style=\"font-family: arial, helvetica, sans-serif;\">automatically<\/span>. It happens in lines 14 and 19. The lock operation is performed <span style=\"font-family: arial, helvetica, sans-serif;\">atomically&nbsp;<\/span>in line 23 using the variadic template <span style=\"font-family: courier new,courier;\">std::lock<\/span>. A variadic template is a template that can accept an arbitrary number of arguments. Here, the arguments are locks. <span style=\"font-family: courier new,courier;\">std::lock<\/span>&nbsp;tries to get all locks in an atomic step. So, he fails or gets all of them. <span style=\"font-family: courier new,courier;\"><\/span><span style=\"font-family: courier new,courier;\"><\/span><\/span> <\/span><\/p>\n<p>In this example, <span style=\"font-family: courier new,courier;\">std::unique_lock<\/span> takes care of the lifetime of the resources, <span style=\"font-family: courier new,courier;\">std::lock<\/span> locks the associated mutex. But you can do it the other way around. In the first step, you lock the mutexes; in the second <span style=\"font-family: courier new,courier;\">std::unique_lock<\/span> takes care of the lifetime of resources. Here is a sketch of the second approach.<\/p>\n<p>&nbsp;<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff none repeat scroll 0% 0%; overflow: auto; width: auto; border-width: 0.1em 0.1em 0.1em 0.8em;\">\n<pre style=\"margin: 0px; line-height: 125%;\">std::lock(a.mut, b.mut);\nstd::lock_guard&lt;std::mutex&gt; guard1(a.mut, std::adopt_lock);\nstd::lock_guard&lt;std::mutex&gt; guard2(b.mut, std::adopt_lock);\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Now, all is fine. The program runs without deadlock.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-4746\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/05\/deadlockResolved.png\" alt=\"deadlockResolved\" width=\"542\" height=\"309\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/05\/deadlockResolved.png 542w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/05\/deadlockResolved-300x171.png 300w\" sizes=\"auto, (max-width: 542px) 100vw, 542px\" \/><span style=\"color: #000000;\"><\/span><br \/>\n<span style=\"color: #000000;\"><\/span><\/p>\n<h3><span style=\"color: #000000;\">A side note: Special deadlocks<br \/>\n<\/span><\/h3>\n<p>It&#8217;s an illusion that only a mutex can produce a deadlock.<strong> Each time a thread has to wait for a resource, a deadlock lurks near while it is holding a resource.<\/strong><\/p>\n<p><span style=\"color: #000000;\">Even a thread is a resource.<br \/>\n<\/span><\/p>\n<p><span style=\"color: #000000;\"><!-- HTML generated using hilite.me --><\/span><\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"> 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ blockJoin.cpp<\/span>\n\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #0000ff;\">#include &lt;mutex&gt;<\/span>\n<span style=\"color: #0000ff;\">#include &lt;thread&gt;<\/span>\n\nstd::mutex coutMutex;\n\n<span style=\"color: #2b91af;\">int<\/span> main(){\n\n  std::<span style=\"color: #0000ff;\">thread<\/span> t([]{\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"Still waiting ...\"<\/span> &lt;&lt; std::endl;\n    std::lock_guard&lt;std::mutex&gt; lockGuard(coutMutex);\n    std::cout &lt;&lt; std::this_thread::get_id() &lt;&lt; std::endl;\n    }\n  );\n\n  {\n    std::lock_guard&lt;std::mutex&gt; lockGuard(coutMutex);\n    std::cout &lt;&lt; std::this_thread::get_id() &lt;&lt; std::endl;\n    t.join();\n  }\n\n}\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #000000;\">The program immediately stands still.<br \/>\n<\/span><\/p>\n<p><span style=\"color: #000000;\"><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-4747\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/05\/blockJoin.png\" alt=\"blockJoin\" width=\"375\" height=\"171\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/05\/blockJoin.png 375w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/05\/blockJoin-300x137.png 300w\" sizes=\"auto, (max-width: 375px) 100vw, 375px\" \/><\/span><\/p>\n<p>What&#8217;s happening? The lock of output stream <span style=\"font-family: courier new,courier;\">std::cout<\/span> and the waiting of the main thread for its child t cause the deadlock. By observing the output, you can easily see in which order the statements will be performed.<\/p>\n<p>In the first step, the main thread executes lines 19 &#8211; 21. It waits in line 21 using the call <span style=\"font-family: courier new,courier;\">t.join()<\/span> until its child t is done with its work package. The main thread is waiting while it locks the output stream. But that&#8217;s precisely the resource the child is&nbsp;waiting for. Two ways to solve this deadlock come to mind.<\/p>\n<p style=\"color: #000000;\">&nbsp;<\/p>\n<ul>\n<li><span style=\"color: #000000;\">The <span style=\"font-family: courier new,courier;\">main t<\/span>hread locks the output stream <span style=\"font-family: courier new,courier;\">std::cout<\/span> after the call <span style=\"font-family: courier new,courier;\">t.join()<\/span>.<\/span><\/li>\n<\/ul>\n<p><span style=\"color: #000000;\"><!-- HTML generated using hilite.me --><\/span><\/p>\n<div style=\"background: #ffffff none repeat scroll 0% 0%; overflow: auto; width: auto; border-width: 0.1em 0.1em 0.1em 0.8em;\">\n<pre style=\"margin: 0px; line-height: 125%; padding-left: 60px;\"><span style=\"color: #000000;\">{\n  t.join();\n  std::lock_guard&lt;std::mutex&gt; lockGuard(coutMutex);\n  std::cout &lt;&lt; std::this_thread::get_id() &lt;&lt; std::endl;\n}\n<\/span><\/pre>\n<\/div>\n<ul>\n<li><span style=\"color: #000000;\">The main thread releases its lock by an additional scope. This is done before the <span style=\"font-family: courier new,courier;\">t.join()<\/span> call.<span style=\"font-family: courier new,courier;\"><\/span><br \/>\n<\/span><\/li>\n<\/ul>\n<p><span style=\"color: #000000;\"><!-- HTML generated using hilite.me --><\/span><\/p>\n<div style=\"background: #ffffff none repeat scroll 0% 0%; overflow: auto; width: auto; border-width: 0.1em 0.1em 0.1em 0.8em;\">\n<pre style=\"margin: 0px; line-height: 125%; padding-left: 60px;\"><span style=\"color: #000000;\">{\n  {\n    std::lock_guard&lt;std::mutex&gt; lockGuard(coutMutex);\n    std::cout &lt;&lt; std::this_thread::get_id() &lt;&lt; std::endl;\n  }\n  t.join();\n}\n<\/span><\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>In the <a href=\"https:\/\/www.modernescpp.com\/index.php\/reader-writer-locks\">next post<\/a>, I&#8217;ll talk about reader-writer locks. Reader-writer locks empower you since C++14 to distinguish between reading and writing threads. So, the contention on the shared variable will be mitigated because an arbitrary number of reading threads can access the shared variable simultaneously. (<strong>Proofreader Alexey Elymanov<\/strong>)<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If the previous post showed something, it&#8217;s that you should use mutexes with great care. That&#8217;s why you should wrap them in a lock.<\/p>\n","protected":false},"author":21,"featured_media":4746,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[366],"tags":[430,433],"class_list":["post-4748","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-multithreading","tag-lock","tag-mutex"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4748","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=4748"}],"version-history":[{"count":2,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4748\/revisions"}],"predecessor-version":[{"id":8059,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4748\/revisions\/8059"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/4746"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=4748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=4748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=4748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}