{"id":4857,"date":"2016-08-20T21:25:18","date_gmt":"2016-08-20T21:25:18","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/ongoing-optimization-relaxed-semantic-with-cppmem\/"},"modified":"2023-10-21T20:11:48","modified_gmt":"2023-10-21T20:11:48","slug":"ongoing-optimization-relaxed-semantic-with-cppmem","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/ongoing-optimization-relaxed-semantic-with-cppmem\/","title":{"rendered":"Ongoing Optimization: Relaxed Semantics with CppMem"},"content":{"rendered":"<p>With the relaxed semantics, we have no synchronizations and ordering constraints on atomic operations.<\/p>\n<p><!--more--><\/p>\n<h2>Relaxed Semantics<\/h2>\n<p>With the relaxed semantics, only the atomicity of the operations on atomics is left.<\/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\n25<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ ongoingOptimizationRelaxedSemantic.cpp<\/span>\n\n<span style=\"color: #0000ff;\">#include &lt;atomic&gt;<\/span>\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #0000ff;\">#include &lt;thread&gt;<\/span>\n\nstd::atomic&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; x{0};\nstd::atomic&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; y{0};\n\n<span style=\"color: #2b91af;\">void<\/span> writing(){  \n  x.store(2000,std::memory_order_relaxed);  \n  y.store(11,std::memory_order_relaxed);\n}\n\n<span style=\"color: #2b91af;\">void<\/span> reading(){  \n  std::cout &lt;&lt; y.load(std::memory_order_relaxed) &lt;&lt; <span style=\"color: #a31515;\">\" \"<\/span>;  \n  std::cout &lt;&lt; x.load(std::memory_order_relaxed) &lt;&lt; std::endl;\n}\n\n<span style=\"color: #2b91af;\">int<\/span> main(){\n  std::<span style=\"color: #0000ff;\">thread<\/span> thread1(writing);\n  std::<span style=\"color: #0000ff;\">thread<\/span> thread2(reading);\n  thread1.join();\n  thread2.join();\n};\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>Now, the questions are very easy to answer. Does the program have well-defined behavior? Which values for x and y are possible? On the one hand, all operations on x and y are atomic. So the program is well-defined. On the other hand, there are no restrictions on the interleaving of the threads. In the end, thread two can see the operations on thread 1 in a different order. So this is the first time in our process of ongoing optimizations that thread two can display x == 0 and y == 1. All combinations of x and y are\u00a0possible.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-4856\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/08\/sukzessiveOptimierungRelaxedSemantikEng.png\" alt=\"sukzessiveOptimierungRelaxedSemantikEng\" width=\"272\" height=\"217\" \/><\/p>\n<p>I&#8217;m curious, what the graph of CppMem will look like for x == 0 and y == 1?<\/p>\n<h3>CppMem<\/h3>\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<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #2b91af;\">int<\/span> main(){\n  atomic_int x= 0;\n  atomic_int y= 0;\n  {{{ { \n      x.store(2000, memory_order_relaxed);\n      y.store(11,memory_order_relaxed);\n      }\n  ||| {\n      y.load(memory_order_relaxed);\n      x.load(memory_order_relaxed);\n      }\n  }}}\n}\n<\/pre>\n<\/div>\n<p>That was the CppMem program. Now to the graph.<\/p>\n<h3>Execution for (y=0,x=2000)<\/h3>\n<p>The graph shows crystal clear unintuitive behavior.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-4830\" style=\"margin: 15px;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/07\/relaxed.png\" alt=\"relaxed\" width=\"527\" height=\"470\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/07\/relaxed.png 527w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/07\/relaxed-300x268.png 300w\" sizes=\"auto, (max-width: 527px) 100vw, 527px\" \/><\/p>\n<p>x reads the value 2000 from the writing thread, but y reads 0 from the main thread. What happens when the reading of y is sequenced before the reading of x? Sequenced before exact means that the operation <strong>e:Rrix<\/strong> <strong>sb<\/strong> is <em>sequenced-before <\/em>the operation <strong>f:Rrix<\/strong>.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>This was the last post in my mini-series about <a href=\"https:\/\/www.modernescpp.com\/index.php\/tag\/ongoingoptimization\">ongoing optimization<\/a>. So, what&#8217;s next? There are a lot of issues with the singleton pattern. I&#8217;m aware of that. However the singleton pattern is an ideal use case for a variable, which has to be initialized in a thread-safe way. From that point on, you can use it without synchronization.<br \/>\nSo in the <a href=\"https:\/\/www.modernescpp.com\/index.php\/thread-safe-initialization-of-a-singleton\">next post<\/a>, I discuss different ways to initialize a singleton in a multithreading environment. You get the performance numbers and can reason about your use cases for the thread-safe initialization of a variable.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>With the relaxed semantics, we have no synchronizations and ordering constraints on atomic operations.<\/p>\n","protected":false},"author":21,"featured_media":4856,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[369],"tags":[434,486,521,504],"class_list":["post-4857","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-multithreading-application","tag-atomics","tag-cppmem","tag-ongoing-optimization","tag-relaxed-semantics"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4857","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=4857"}],"version-history":[{"count":2,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4857\/revisions"}],"predecessor-version":[{"id":8533,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4857\/revisions\/8533"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/4856"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=4857"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=4857"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=4857"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}