{"id":5807,"date":"2019-10-29T09:23:28","date_gmt":"2019-10-29T09:23:28","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-20-concurrency\/"},"modified":"2023-06-26T09:58:09","modified_gmt":"2023-06-26T09:58:09","slug":"c-20-concurrency","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-20-concurrency\/","title":{"rendered":"C++20: Concurrency"},"content":{"rendered":"<p>This post concludes my overview of C++20. Today&#8217;s post is about the concurrency features in the next C++ standard.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5806\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/TimelineCpp20Concurrency.png\" alt=\"TimelineCpp20Concurrency\" width=\"650\" height=\"254\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/TimelineCpp20Concurrency.png 1066w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/TimelineCpp20Concurrency-300x117.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/TimelineCpp20Concurrency-1024x400.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/TimelineCpp20Concurrency-768x300.png 768w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<h2>Concurrency<\/h2>\n<p>C++20 has various concurrency improvements.<\/p>\n<h3><span style=\"font-family: courier new, courier;\">std::atomic_ref&lt;T&gt;<\/span><\/h3>\n<p>The class template <span style=\"font-family: courier new, courier;\">std::atomic_ref<\/span> applies atomic operations to the referenced non-atomic object. Concurrent writing and reading of the referenced object is no data race. The lifetime of the referenced object must exceed the lifetime of the atomic_ref. Accessing a subobject of the referenced object with an <span style=\"font-family: courier new, courier;\">atomic_ref<\/span> is not thread-safe.<\/p>\n<p>Accordingly to <span style=\"font-family: courier new, courier;\">std::atomic, std::atomic_ref<\/span> can be specialized and supports specializations for the built-in data types.<\/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: #006699; font-weight: bold;\">struct<\/span> Counters {\r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> a;\r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> b;\r\n};\r\n\r\nCounter counter;<br \/>\r\nstd<span style=\"color: #555555;\">::<\/span>atomic_ref<span style=\"color: #555555;\">&lt;<\/span>Counters<span style=\"color: #555555;\">&gt;<\/span> cnt(counter);\r\n<\/pre>\n<\/div>\n<h3><span style=\"font-family: courier new, courier;\">std::atomic&lt;std::shared_ptr&lt;T&gt;&gt;<\/span> and <span style=\"font-family: courier new, courier;\">std::atomic&lt;std::weak_ptr&lt;T&gt;&gt;<\/span><\/h3>\n<p><span style=\"font-family: courier new, courier;\">std::shared_ptr<\/span> is the only non-atomic data type on which you can apply atomic operations. First, let me write about the motivation for this exception. The C++ committee saw the necessity that instances of<span style=\"font-family: courier new, courier;\"> std::shared_ptr<\/span> should provide a minimum atomicity guarantee in multithreading programs. What is this minimal atomicity guarantee for <span style=\"font-family: courier new, courier;\">std::shared_ptr<\/span>? The control block of the <span style=\"font-family: courier new, courier;\">std::shared_ptr<\/span> is thread-safe. This means that the increase and decrease operations of the reference counter are atomic. You also have the guarantee that the resource is destroyed exactly once.<\/p>\n<p>Boost describes the assertions that a std::shared_ptr provides.<\/p>\n<ol>\n<li>A <span style=\"font-family: courier new, courier;\">shared_ptr<\/span> instance can be \u201cread\u201d (accessed using only constant operations) simultaneously by multiple threads.<\/li>\n<li>Different <span style=\"font-family: courier new, courier;\">shared_ptr<\/span> instances can be \u201cwritten to\u201d (accessed using mutable operations such as operator= or reset) simultaneously by multiple threads (even when these instances are copies and share the exact reference count underneath).<\/li>\n<\/ol>\n<p>With C++20 we get two new smart pointers: <span style=\"font-family: courier new, courier;\">std::atomic&lt;std::shared_ptr&lt;T&gt;&gt;<\/span> and <span style=\"font-family: courier new, courier;\">std::atomic&lt;std::weak_ptr&lt;T&gt;&gt;.<\/span><\/p>\n<\/p>\n<h3>Floating Point Atomics<\/h3>\n<p>In addition to C++11, you can create atomics for integral types and floating points. This is quite convenient when you have a floating-point number concurrently incremented by various threads. With a floating-point atomic, you don&#8217;t need to protect the floating pointer number.<\/p>\n<h3>Waiting on Atomics<\/h3>\n<p><span style=\"font-family: courier new, courier;\">std::atomic_flag<\/span> is an atomic boolean. It has a clear and set state. For simplicity reasons, I call the clear state <span style=\"font-family: courier new, courier;\">false<\/span> and the set state <span style=\"font-family: courier new, courier;\">true<\/span>. Its <span style=\"font-family: courier new, courier;\">clear<\/span> method enables you to set its value to <span style=\"font-family: courier new, courier;\">false<\/span>. With the <span style=\"font-family: courier new, courier;\">test_and_set<\/span> method, you can set the value to <span style=\"font-family: courier new, courier;\">true<\/span> and return the previous value. There is no method to ask for the current value. This will change with C++20. With C++20, a&nbsp; <span style=\"font-family: courier new, courier;\">std::atomic_flag<\/span> has a <span style=\"font-family: courier new, courier;\">test<\/span> method.<\/p>\n<p>Additionally, <span style=\"font-family: courier new, courier;\">std::atomic_flag<\/span> can be used for thread synchronization via the methods<span style=\"font-family: courier new, courier;\"> notify_one, notify_all,<\/span> and <span style=\"font-family: courier new, courier;\">wait<\/span>. Notifying and waiting is with C++20 available on all partial and full specialization of <span style=\"font-family: Courier New, Courier, monospace;\">std::atomic<\/span> (bools, integrals, floats and pointers) and <span style=\"font-family: Courier New, Courier, monospace;\">std::atomic_ref.<\/span><\/p>\n<h3>Semaphores, Latches, and Barriers<\/h3>\n<p>All three types are means to synchronize threads.<\/p>\n<h4>Semaphores<\/h4>\n<p>Semaphores are a synchronization mechanism that controls concurrent access to a shared resource. A counting semaphore, such as the one in C++20, is a special semaphore with a counter bigger than zero. The counter is initialized in the constructor. Acquiring the semaphore decreases the counter, and releasing the semaphore increases the counter. If a thread tries to acquire the semaphore when the counter is zero, the thread will block until another thread increments the counter by releasing the semaphore.<\/p>\n<h4>Latches and Barriers<\/h4>\n<p>Latches and barriers are simple thread synchronization mechanisms that enable some threads to block until a counter becomes zero.<\/p>\n<p>What are the differences between these two mechanisms to synchronize threads? You can use a<span style=\"font-family: Courier New, Courier, monospace;\"> std::latch<\/span> only once, but you can use a <span style=\"font-family: Courier New, Courier, monospace;\">std::barrier<\/span> more than once. A<span style=\"font-family: Courier New, Courier, monospace;\"> std::latch <\/span>is useful for managing one task by multiple threads; a<span style=\"font-family: Courier New, Courier, monospace;\"> std::barrier<\/span> is useful for managing repeated tasks by multiple threads. Additionally, a<span style=\"font-family: Courier New, Courier, monospace;\"> std::barrier<\/span> can adjust the counter in each iteration.<\/p>\n<p>The following code snippet is from Proposal <a href=\"http:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2014\/n4204.html\">N4204<\/a>.<\/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: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">DoWork<\/span>(threadpool<span style=\"color: #555555;\">*<\/span> pool) {\r\n\r\n    latch completion_latch(NTASKS);   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #007788; font-weight: bold;\">int<\/span> i <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">0<\/span>; i <span style=\"color: #555555;\">&lt;<\/span> NTASKS; <span style=\"color: #555555;\">++<\/span>i) {\r\n        pool<span style=\"color: #555555;\">-&gt;<\/span>add_task([<span style=\"color: #555555;\">&amp;<\/span>] {          <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n\r\n        <span style=\"color: #0099ff; font-style: italic;\">\/\/ perform work<\/span>\r\n        ...\r\n        completion_latch.count_down();<span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n        })};                          <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n    }\r\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ Block until work is done<\/span>\r\n    completion_latch.wait();          <span style=\"color: #0099ff; font-style: italic;\">\/\/ (5)<\/span>\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The <span style=\"font-family: Courier New, Courier, monospace;\">std::latch completion_latch<\/span> is in its constructor set to <span style=\"font-family: Courier New, Courier, monospace;\">NTASKS <\/span>(line 1). The thread pool executes<span style=\"font-family: Courier New, Courier, monospace;\"> NTASKS <\/span>(lines 2 &#8211; 3) jobs. At the end of each job (line 4), the counter is decremented. Line 5 is the barrier for the thread running the function <span style=\"font-family: Courier New, Courier, monospace;\">DoWork <\/span>and hence for the small workflow. This thread is blocked until all tasks have been finished.<\/p>\n<h3><span style=\"font-family: Courier New, Courier, monospace;\">std::jthread<\/span><\/h3>\n<p><span style=\"font-family: Courier New, Courier, monospace;\">std::jthread<\/span> stands for joining thread. In addition to <span style=\"font-family: Courier New, Courier, monospace;\">std::thread<\/span> from C++11, <span style=\"font-family: Courier New, Courier, monospace;\">std::jthread<\/span> can automatically join the started thread and can be interrupted.<\/p>\n<p>Here is the non-intuitive behaviour of<span style=\"font-family: Courier New, Courier, monospace;\"> std::thread<\/span>. If a <span style=\"font-family: Courier New, Courier, monospace;\">std::thread <\/span>is still joinable, <span style=\"font-family: Courier New, Courier, monospace;\">std::terminate<\/span> is called in its destructor. A thread <span style=\"font-family: Courier New, Courier, monospace;\">thr <\/span>is joinable if either<span style=\"font-family: Courier New, Courier, monospace;\"> thr.join()<\/span> nor <span style=\"font-family: Courier New, Courier, monospace;\">thr.detach() <\/span>was called.<\/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: #009999;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ threadJoinable.cpp<\/span><br \/><br \/>#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;thread&gt;<\/span>\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/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    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>boolalpha;\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> thr{[]{ std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Joinable std::thread\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl; }};\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"thr.joinable(): \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> thr.joinable() <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\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>When executed, the program terminates.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5528\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/10\/threadJoinable.png\" alt=\"threadJoinable\" width=\"500\" height=\"279\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/10\/threadJoinable.png 644w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/10\/threadJoinable-300x167.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p>Both executions of the program<span style=\"font-family: Courier New, Courier, monospace;\"> <\/span>terminate. In the second run, the thread <span style=\"font-family: Courier New, Courier, monospace;\">thr <\/span>has enough time to display its message: \u201c<span style=\"font-family: Courier New, Courier, monospace;\">Joinable std::thread<\/span>\u201d.<\/p>\n<p>In the next example, I replace the header <span style=\"font-family: Courier New, Courier, monospace;\">&lt;thread&gt;<\/span> with &#8220;<span style=\"font-family: Courier New, Courier, monospace;\">jthread.hpp<\/span>&#8221; and, therefore, use <span style=\"font-family: Courier New, Courier, monospace;\">std::jthread<\/span> from the upcoming C++20 standard.<\/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: #009999;\"><span style=\"color: #009999;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ jthreadJoinable.cpp<\/span><\/span><br \/><br \/>#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include \"jthread.hpp\"<\/span>\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/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    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>boolalpha;\r\n    std<span style=\"color: #555555;\">::<\/span>jthread thr{[]{ std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Joinable std::jthread\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl; }};\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"thr.joinable(): \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> thr.joinable() <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\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>Now, the thread <span style=\"font-family: courier new, courier;\">thr<\/span> automatically joins in its destructor such as in this case if still joinable.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5529\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/10\/jthreadJoinable.png\" alt=\"jthreadJoinable\" width=\"350\" height=\"177\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/10\/jthreadJoinable.png 443w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/10\/jthreadJoinable-300x152.png 300w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>I provided in the last four posts an overview of the new features in C++20. After the overview, let me dive into the details. My <a href=\"https:\/\/www.modernescpp.com\/index.php\/concepts-two-extrems-and-the-solution\">next post<\/a> is about concepts.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post concludes my overview of C++20. Today&#8217;s post is about the concurrency features in the next C++ standard.<\/p>\n","protected":false},"author":21,"featured_media":5806,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[434,431],"class_list":["post-5807","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-atomics","tag-semaphores"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5807","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=5807"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5807\/revisions"}],"predecessor-version":[{"id":6766,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5807\/revisions\/6766"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5806"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5807"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5807"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5807"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}