{"id":557,"date":"2019-08-04T15:26:12","date_gmt":"2019-08-04T22:26:12","guid":{"rendered":"http:\/\/35.243.195.209\/?p=557"},"modified":"2019-08-04T15:26:43","modified_gmt":"2019-08-04T22:26:43","slug":"mutex-in-c-and-java","status":"publish","type":"post","link":"https:\/\/nanzhou.cc\/index.php\/2019\/08\/04\/mutex-in-c-and-java\/","title":{"rendered":"Mutex in C++ and Java"},"content":{"rendered":"<h2>Summary<\/h2>\n<p>In this post, I will introduce the correct way to use <code>mutex<\/code> in C++, compared to Java. <\/p>\n<h2>Conclusion<\/h2>\n<ol>\n<li>Try not to use <code>std::mutex<\/code> directly. <\/li>\n<li>Use <code>std::unique_lock<\/code>, <code>std::lock_guard<\/code>, or <code>std::scoped_lock (since C++17)<\/code> to manage locking in a more exception-safe manner.<\/li>\n<li>Undefined behaviors will happen if<br \/>\na). A mutex is destroyed while still owned by any threads;<br \/>\nb). A thread terminates while owning a mutex;<br \/>\nc). <code>std::mutex.lock()<\/code> is called by a thread that already owns the mutex;<br \/>\nd). <code>std::mutex.unlock()<\/code> is called but the mutex is not currently locked by the calling thread.<\/li>\n<li>Use <code>std::condition_variable<\/code> to control dependency among threads. <\/li>\n<li>In Java, <code>java.util.concurrent.Semaphore<\/code> is able to achieve both exclusive blocks and dependency control among threads. <\/li>\n<\/ol>\n<p>Some experience below is helpful for concurrency coding challenges. <\/p>\n<ol>\n<li>Use internal boolean or integer variables to help to manage dependencies among threads; use these variables to make some threads sleeping before one thread uses <code>std::condition_variable<\/code> to notify them. <\/li>\n<li>You may need multiple global <code>std::mutex<\/code> instances and the same number of <code>std::condition_variable<\/code> instances to transfer computation from a thread to another thread. <\/li>\n<\/ol>\n<h2>Details<\/h2>\n<h3>1. Managment of exclusive blocks<\/h3>\n<p>Use <code>std::unique_lock<\/code>. Examples are shown below. <\/p>\n<pre><code class=\"language-cpp\">#include &lt;mutex&gt;\n#include &lt;thread&gt;\n#include &lt;iostream&gt;\n#include &lt;vector&gt;\n\nint main() {\n    int counter = 0;\n    std::mutex counter_mutex;\n    std::vector&lt;std::thread&gt; threads;\n\n    auto worker_task = [&amp;](int id) {\n    \/\/ acquire mutex when unique_lock is created\n        std::unique_lock&lt;std::mutex&gt; lock(counter_mutex);\n        ++counter;\n        std::cout &lt;&lt; id &lt;&lt; &quot;, initial counter: &quot; &lt;&lt; counter &lt;&lt; &#039;\\n&#039;;\n        \/\/ gurantee to release lock after leaving the block, including exceptions, goto, return, etc. \n    };\n\n    for (int i = 0; i &lt; 10; ++i) threads.emplace_back(worker_task, i);\n\n    for (auto &amp;thread : threads) thread.join();\n}<\/code><\/pre>\n<p><code>std::unique_lock<\/code> is able to ensure that every time only one thread is running codes in the block. Compared to using <code>std::mutex<\/code> directly, <code>std::unique_lock<\/code> also ensures that the mutex will unlock when leaving the scope where the <code>std::unique_lock<\/code> is defined.<\/p>\n<h3>2. Dependency among threads<\/h3>\n<p>Use <code>std::condition_variable<\/code> to manage dependency among threads. <code>std::condition_variable<\/code> use <code>wait(unique_lock)<\/code> and <code>notify_all()<\/code> or <code>notify_one()<\/code> heavily. It talks to <code>std::unique_lock<\/code> and often use internal variables (boolean or integer) to help determining the execution order. Examples are shown below. <\/p>\n<pre><code class=\"language-cpp\">#include &lt;iostream&gt;\n#include &lt;thread&gt;\n#include &lt;condition_variable&gt;\n#include &lt;mutex&gt;\n#include &lt;chrono&gt;\n#include &lt;queue&gt;\nusing namespace std;\n\ncondition_variable cond_var;\nmutex m;\n\nint main() {\n    int value = 100;\n    bool notified = false;\n    thread reporter([&amp;]() {\n        unique_lock&lt;mutex&gt; lock(m);\n        while (!notified) {\n            cond_var.wait(lock);\n        }\n        cout &lt;&lt; &quot;The value is &quot; &lt;&lt; value &lt;&lt; endl;\n    });\n\n    thread assigner([&amp;]() {\n        value = 20;\n        notified = true;\n        cond_var.notify_one();\n    });\n\n    reporter.join();\n    assigner.join();\n    return 0;\n}<\/code><\/pre>\n<p>In the above codes, we use a boolean <code>notified <\/code> to guarantee that the reporter always works after the assigner. Note that we use a while loop in the reporter since generally, the function is notified to wake up by a call in another thread either to member notify_one or to member notify_all, but certain implementations may produce <strong>spurious wake-up<\/strong> calls without any of these functions being called. Therefore, we use a while loop to avoid spurious wake-up. <\/p>\n<h3>3. Semaphore makes life easier<\/h3>\n<p>Java&#8217;s Semaphore contains the functionality of both <code>mutex<\/code> and <code>condition_variable<\/code> in C++. See the following coding challenge for example. <\/p>\n<pre><code class=\"language-java\">import java.util.concurrent.*;\nclass FooBar {\n    private int n;\n    Semaphore s1, s2;\n    public FooBar(int n) {\n        this.n = n;\n        s1 = new Semaphore(1);\n        s2 = new Semaphore(0);\n    }\n\n    public void foo(Runnable printFoo) throws InterruptedException {\n\n        for (int i = 0; i &lt; n; i++) {\n            s1.acquire();\n            \/\/ printFoo.run() outputs &quot;foo&quot;\n            printFoo.run();\n            \/\/ release acts like notifying\n            s2.release();\n        }\n    }\n\n    public void bar(Runnable printBar) throws InterruptedException {\n        for (int i = 0; i &lt; n; i++) {\n            s2.acquire();\n            \/\/ printBar.run() outputs &quot;bar&quot;\n            printBar.run();\n            s1.release();\n        }\n    }\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Summary In this post, I will introduce the correct way to use mutex in C++, compared to Java. Conclusion Try not to use std::mutex directly. Use std::unique_lock, std::lock_guard, or std::scoped_lock (since C++17) to manage locking in a more exception-safe manner. Undefined behaviors will happen if a). A mutex is destroyed while still owned by any&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,33,32,31,5],"tags":[],"class_list":["post-557","post","type-post","status-publish","format-standard","hentry","category-c","category-java","category-muitl-thread","category-parallel-computation","category-proglang"],"_links":{"self":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/557","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/comments?post=557"}],"version-history":[{"count":2,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/557\/revisions"}],"predecessor-version":[{"id":559,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/557\/revisions\/559"}],"wp:attachment":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/media?parent=557"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/categories?post=557"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/tags?post=557"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}