{"id":4810,"date":"2016-07-09T20:59:28","date_gmt":"2016-07-09T20:59:28","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/memory-order-consume\/"},"modified":"2023-06-26T12:50:33","modified_gmt":"2023-06-26T12:50:33","slug":"memory-order-consume","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/memory-order-consume\/","title":{"rendered":"memory_order_consume"},"content":{"rendered":"<p><span style=\"font-family: courier new,courier;\">std::memory_order_consume<\/span> is the most legendary of the<a href=\"https:\/\/www.modernescpp.com\/index.php\/synchronization-and-ordering-constraints\"> six memory models<\/a>. That&#8217;s for two reasons. On the one hand, <span style=\"font-family: courier new,courier;\">std::memory_order_consume<\/span> is extremely hard to get. On the other hand &#8211; that may change in the future &#8211; no compiler supports it.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<p>How can it happen that a compiler supports the C++11 standard but doesn&#8217;t support the memory model <span style=\"font-family: courier new,courier;\">std::memory_order_consume<\/span>? The answer is that compiler maps <span style=\"font-family: courier new,courier;\">std::memory_order_consume<\/span> to <span style=\"font-family: courier new,courier;\">std::memory_order_acquire<\/span>. That is fine because both are load or acquire operations. <span style=\"font-family: courier new,courier;\">std::memory_order_consume<\/span> requires weaker <a href=\"https:\/\/www.modernescpp.com\/index.php\/synchronization-and-ordering-constraints\">synchronization and ordering constraints<\/a>. So the release-acquire ordering is potentially slower than the release-consume ordering, but the crucial point is well-defined.&nbsp;<\/p>\n<p>To understand the release-consume ordering, it&#8217;s a good idea to compare it with the release-acquire ordering. I speak in the post explicitly from the release-acquire ordering and not from the <a href=\"https:\/\/www.modernescpp.com\/index.php\/acquire-release-semantic\">acquire-release semantic<\/a> to emphasize the strong relationship of <span style=\"font-family: courier new,courier;\">std::memory_order_consume<\/span> and <span style=\"font-family: courier new,courier;\">std::memory_order_acquire<\/span>.<\/p>\n<\/p>\n<h2>Release-acquire ordering<\/h2>\n<p>As a starting point, I use a program with two threads <span style=\"font-family: courier new,courier;\">t1<\/span> and <span style=\"font-family: courier new,courier;\">t2. t1<\/span> plays the role of the producer, <span style=\"font-family: courier new,courier;\">t2<\/span> the role of the consumer. The atomic variable <span style=\"font-family: courier new,courier;\">ptr<\/span> helps to synchronize the producer and consumer.<\/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\r\n 2\r\n 3\r\n 4\r\n 5\r\n 6\r\n 7\r\n 8\r\n 9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\n30\r\n31\r\n32\r\n33\r\n34\r\n35\r\n36\r\n37\r\n38\r\n39<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ acquireRelease.cpp<\/span>\r\n\r\n<span style=\"color: #0000ff;\">#include &lt;atomic&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;thread&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;string&gt;<\/span>\r\n \r\nstd::atomic&lt;std::string*&gt; ptr;\r\n<span style=\"color: #2b91af;\">int<\/span> data;\r\nstd::atomic&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; atoData;\r\n \r\n<span style=\"color: #2b91af;\">void<\/span> producer(){\r\n    std::string* p  = <span style=\"color: #0000ff;\">new<\/span> std::string(<span style=\"color: #a31515;\">\"C++11\"<\/span>);\r\n    data = 2011;\r\n    atoData.store(2014,std::memory_order_relaxed);\r\n    ptr.store(p, std::memory_order_release);\r\n}\r\n \r\n<span style=\"color: #2b91af;\">void<\/span> consumer(){\r\n    std::string* p2;\r\n    <span style=\"color: #0000ff;\">while<\/span> (!(p2 = ptr.load(std::memory_order_acquire)));\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"*p2: \"<\/span> &lt;&lt; *p2 &lt;&lt; std::endl;\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"data: \"<\/span> &lt;&lt; data &lt;&lt; std::endl;\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"atoData: \"<\/span> &lt;&lt; atoData.load(std::memory_order_relaxed) &lt;&lt; std::endl;\r\n}\r\n \r\n<span style=\"color: #2b91af;\">int<\/span> main(){\r\n    \r\n    std::cout &lt;&lt; std::endl;\r\n    \r\n    std::<span style=\"color: #0000ff;\">thread<\/span> t1(producer);\r\n    std::<span style=\"color: #0000ff;\">thread<\/span> t2(consumer);\r\n    \r\n    t1.join();\r\n    t2.join();\r\n    \r\n    std::cout &lt;&lt; std::endl;\r\n    \r\n}\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Before I analyze the program, I want to introduce a small variation. I replace in line 21 the memory model <span style=\"font-family: courier new,courier;\">std::memory_order_acquire<\/span> with <span style=\"font-family: courier new,courier;\">std::memory_order_consume<\/span>.<\/p>\n<h2>Release-consume ordering<\/h2>\n<p>&nbsp;<\/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\r\n 2\r\n 3\r\n 4\r\n 5\r\n 6\r\n 7\r\n 8\r\n 9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\n30\r\n31\r\n32\r\n33\r\n34\r\n35\r\n36\r\n37\r\n38\r\n39<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ acquireConsume.cpp<\/span>\r\n\r\n<span style=\"color: #0000ff;\">#include &lt;atomic&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;thread&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;string&gt;<\/span>\r\n \r\nstd::atomic&lt;std::string*&gt; ptr;\r\n<span style=\"color: #2b91af;\">int<\/span> data;\r\nstd::atomic&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; atoData;\r\n \r\n<span style=\"color: #2b91af;\">void<\/span> producer(){\r\n    std::string* p  = <span style=\"color: #0000ff;\">new<\/span> std::string(<span style=\"color: #a31515;\">\"C++11\"<\/span>);\r\n    data = 2011;\r\n    atoData.store(2014,std::memory_order_relaxed);\r\n    ptr.store(p, std::memory_order_release);\r\n}\r\n \r\n<span style=\"color: #2b91af;\">void<\/span> consumer(){\r\n    std::string* p2;\r\n    <span style=\"color: #0000ff;\">while<\/span> (!(p2 = ptr.load(std::memory_order_consume)));\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"*p2: \"<\/span> &lt;&lt; *p2 &lt;&lt; std::endl;\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"data: \"<\/span> &lt;&lt; data &lt;&lt; std::endl;\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"atoData: \"<\/span> &lt;&lt; atoData.load(std::memory_order_relaxed) &lt;&lt; std::endl;\r\n}\r\n \r\n<span style=\"color: #2b91af;\">int<\/span> main(){\r\n    \r\n    std::cout &lt;&lt; std::endl;\r\n    \r\n    std::<span style=\"color: #0000ff;\">thread<\/span> t1(producer);\r\n    std::<span style=\"color: #0000ff;\">thread<\/span> t2(consumer);\r\n    \r\n    t1.join();\r\n    t2.join();\r\n    \r\n    std::cout &lt;&lt; std::endl;\r\n    \r\n}\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>That was easy. But now, the program has undefined behavior. That statement is very hypothetical because my compiler implements <span style=\"font-family: courier new,courier;\">std::memory_order_consume<\/span> by <span style=\"font-family: courier new,courier;\">std::memory_order_acquire.<\/span> So under the hood, both program does the same.<\/p>\n<h2>Release-acquire versus Release-consume ordering<\/h2>\n<p>The output of the programs is identical.<\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-4808\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/07\/acquireReleaseConsume.png\" alt=\"acquireReleaseConsume\" width=\"429\" height=\"306\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/07\/acquireReleaseConsume.png 429w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/07\/acquireReleaseConsume-300x214.png 300w\" sizes=\"auto, (max-width: 429px) 100vw, 429px\" \/><\/p>\n<p>Although I repeat myself, I want to sketch in a few words why the first program <span style=\"font-family: courier new,courier;\">acquireRelease.cpp<\/span> is well defined.<\/p>\n<p>The store operation in line 16 synchronizes-with the load operation in line 21. The reason is, that the store operation uses <span style=\"font-family: courier new,courier;\">std::memory_order_release<\/span>, and the load operation uses <span style=\"font-family: courier new,courier;\">std::memory_order_acquire<\/span>. That was the synchronization. What about the ordering constraints of the release-acquire ordering? The release-acquire ordering guarantees that all operations before the store operation (line 16) are available after the load operation (line 21). So the release-acquire operation orders, in addition to the access on the non-atomic variable <span style=\"font-family: courier new,courier;\">data<\/span> (line 14) and the atomic variable <span style=\"font-family: courier new,courier;\">atoData<\/span> (line 15). That holds, although <span style=\"font-family: courier new,courier;\">atoData<\/span> uses the std::memory_order_relaxed memory model.<\/p>\n<p>The key question is. What happens if I replace the program <span style=\"font-family: courier new,courier;\">std::memory_order_acquire<\/span> with <span style=\"font-family: courier new,courier;\">std::memory_order_consume<\/span>?<\/p>\n<h3>Data dependencies with std::memory_order_consume<\/h3>\n<p>The<span style=\"font-family: courier new,courier;\"> std::memory_order_consume<\/span> is about data dependencies on atomics. Data dependencies exist in two ways, at first <em>carries-a-dependency-to<\/em> in a thread and <em>dependency-ordered_before<\/em> between two threads. Both dependencies introduce a <em>happens-before<\/em> relation. That is the kind of relation a well-defined program needs.&nbsp; But what means <em>carries-a-dependency-to<\/em> and <em>dependency-order-before<\/em>?<\/p>\n<ul>\n<li><em><strong>carries-a-dependency-to:&nbsp;<\/strong><\/em>If the result of an operation A is used as an operand of an operation B, then:&nbsp;A<em> carries-a-dependency-to<\/em> B.<\/li>\n<li><strong><em>dependency-ordered-before: <\/em><\/strong>A store operation (with <span style=\"font-family: courier new,courier;\">std::memory_order_release, std::memory_order_acq_rel <\/span>or<span style=\"font-family: courier new,courier;\"> std::memory_order_seq_cst<\/span>), is <em>dependency-ordered-before<\/em> a load operation B (with <span style=\"font-family: courier new,courier;\">std::memory_order_consume<\/span>) if the result of the load operation B is used in a further operation C in the same thread. Operations B and C have to be in the same thread.<\/li>\n<\/ul>\n<p>Of course, I know from experience that both definitions are difficult to digest. So I will use a graphic to explain them visually.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-4809\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/07\/dependency.png\" alt=\"dependency\" style=\"margin: 15px;\" width=\"899\" height=\"356\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/07\/dependency.png 899w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/07\/dependency-300x119.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/07\/dependency-768x304.png 768w\" sizes=\"auto, (max-width: 899px) 100vw, 899px\" \/><\/p>\n<p>The expression <span style=\"font-family: courier new,courier;\">ptr.store(p, std::memory_order_release)<\/span>&nbsp;is <em>dependency-ordered-before<\/em><span style=\"font-family: courier new,courier;\"> while (!(p2 = ptr.load(std::memory_order_consume)))<\/span>, because in the following line <span style=\"font-family: courier new,courier;\">std::cout &lt;&lt; &#8220;*p2: &#8221; &lt;&lt; *p2 &lt;&lt; std::endl<\/span> the result of the load operation will be read. Further, holds:&nbsp;<span style=\"font-family: courier new,courier;\">while (!(p2 = ptr.load(std::memory_order_consume))&nbsp;<em>carries-a-dependency-to<\/em>&nbsp;<span style=\"font-family: courier new,courier;\">std::cout &lt;&lt; &#8220;*p2: &#8221; &lt;&lt; *p2 &lt;&lt; std::endl<\/span><\/span><span style=\"font-family: courier new,courier;\">, <\/span>because the output of <span style=\"font-family: courier new,courier;\">*p2<\/span> uses the result of the <span style=\"font-family: courier new,courier;\">ptr.load<\/span> operation.<span style=\"font-family: courier new,courier;\"><\/span><\/p>\n<p>But we have no guarantee for the following outputs of <span style=\"font-family: courier new,courier;\">data<\/span> and <span style=\"font-family: courier new,courier;\">atoData.<\/span> That&#8217;s because both have no <em>carries-a-dependency<\/em> relation to the<span style=\"font-family: courier new,courier;\"> ptr.load<\/span> operation. But it gets even worse. Because data is a non-atomic variable, there is a&nbsp;<a href=\"https:\/\/www.modernescpp.com\/index.php\/threads-sharing-data\">race condition <\/a>on <span style=\"font-family: courier new,courier;\">data. <\/span>The reason is that both threads can access <span style=\"font-family: courier new,courier;\">data<\/span> simultaneously, and thread t1 wants to modify <span style=\"font-family: courier new,courier;\">data.<\/span> Therefore, the program is undefined.&nbsp;<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>I admit that was a challenging post. In the <a href=\"https:\/\/www.modernescpp.com\/index.php\/acquire-release-semantic-the-typical-misunderstanding\">next post<\/a>, I deal with the typical misunderstanding of the acquire-release semantic. That happens if the acquire operation is performed before the release operation.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>std::memory_order_consume is the most legendary of the six memory models. That&#8217;s for two reasons. On the one hand, std::memory_order_consume is extremely hard to get. On the other hand &#8211; that may change in the future &#8211; no compiler supports it.<\/p>\n","protected":false},"author":21,"featured_media":4808,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[368],"tags":[505,434,523],"class_list":["post-4810","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-multithreading-memory-model","tag-acquire-release-semantic","tag-atomics","tag-memory_order_consume"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4810","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=4810"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4810\/revisions"}],"predecessor-version":[{"id":6965,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4810\/revisions\/6965"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/4808"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=4810"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=4810"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=4810"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}