{"id":4799,"date":"2016-06-28T06:25:16","date_gmt":"2016-06-28T06:25:16","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/synchronization-and-ordering-constraints\/"},"modified":"2023-06-26T12:51:56","modified_gmt":"2023-06-26T12:51:56","slug":"synchronization-and-ordering-constraints","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/synchronization-and-ordering-constraints\/","title":{"rendered":"Synchronization and Ordering Constraints"},"content":{"rendered":"<p>In this post, our tour through the c++ memory model goes one step deeper. Until now, the posts were only about the atomicity of the atomic data types, but&nbsp;now we deal with the synchronization and ordering constraints of the operations.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<p>You can not configure the atomicity of an atomic data type, but you can adjust very accurately the synchronisation and ordering constraints of atomic operations. Leverage, which is unique to C++. That&#8217;s impossible in the C#&#8221;s or Java&#8217;s memory model.<\/p>\n<h2>The six variants of the C++ memory model<\/h2>\n<p>C++ has six variants of the memory model. The default for atomic operations is <span style=\"font-family: courier new,courier;\">std::memory_order_seq_cst.<\/span> But you can explicitly specify one of the other five. But what has C++11 to offer?<br \/>&nbsp;<\/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: #0000ff;\">enum<\/span> memory_order{\r\n  memory_order_relaxed,\r\n  memory_order_consume,\r\n  memory_order_acquire,\r\n  memory_order_release,\r\n  memory_order_acq_rel,\r\n  memory_order_seq_cst\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>It helps to answer two questions to get a system into the six memory models.<\/p>\n<ol>\n<li>For which type of atomic operations should you use the memory model?<\/li>\n<li>Which synchronization and ordering constraints are defined by the memory model?<\/li>\n<\/ol>\n<p>The rest of this post is about answering these questions. So what are the types of atomic operations?<\/p>\n<\/p>\n<h3>Types of atomic operations<\/h3>\n<p>The memory model deals with reading and\/or writing atomic operations.<\/p>\n<ul>\n<li><strong>read operation: <\/strong><span style=\"font-family: courier new,courier;\">memory_order_acquire<\/span> and <span style=\"font-family: courier new,courier;\">memory_order_consume<\/span><span style=\"font-family: courier new,courier;\"><\/span><\/li>\n<li><strong>write operation: <\/strong>memory_order_release<span style=\"font-family: courier new,courier;\"> <\/span><span style=\"font-family: courier new,courier;\"><\/span><\/li>\n<li><strong>read-modify-write operation: <\/strong><span style=\"font-family: courier new,courier;\">memory_order_acq_rel<\/span> and <span style=\"font-family: courier new,courier;\">memory_order_seq_cs<\/span>t&nbsp; <span style=\"font-family: courier new,courier;\"><\/span><\/li>\n<\/ul>\n<p><span style=\"font-family: courier new,courier;\">memory_order_relaxed<\/span> defines no synchronisation and ordering constraints. So it will not fit in this taxonomy.<\/p>\n<p>&nbsp;<\/p>\n<p>The table orders the atomic operations based on their reading and\/or writing characteristics.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-4798\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/06\/atomicOperationsReadWriteEng.png\" alt=\"atomicOperationsReadWriteEng\" width=\"700\" height=\"465\" style=\"margin: 15px;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/06\/atomicOperationsReadWriteEng.png 809w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/06\/atomicOperationsReadWriteEng-300x199.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/06\/atomicOperationsReadWriteEng-768x510.png 768w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/p>\n<p>If you use an atomic operation atomVar.load(5) with a memory model designed for a write or read-modify-write operation, the writing part has no effect. So an <span style=\"font-family: courier new,courier;\">atomVar.load(5,std, std::memory_order_acq_rel)<\/span> is equivalent to an <span style=\"font-family: courier new,courier;\">atomVar.load(5,std::memory_order_acquire)<\/span>, an <span style=\"font-family: courier new,courier;\">atomVar.load(5, std::memory_order_release)<\/span> is equivalent to an <span style=\"font-family: courier new,courier;\">atomVar.load(5, std::memory_order_relaxed)<\/span>.<\/p>\n<h3>The different synchronization and ordering constraints<\/h3>\n<p>There are three different types of synchronization and ordering constraints in C++11:&nbsp;<\/p>\n<ul>\n<li><strong>Sequential consistency<\/strong>: <span style=\"font-family: courier new,courier;\">memory_order_seq_cst&nbsp;<\/span><\/li>\n<li><strong>Acquire-release<\/strong>: <span style=\"font-family: courier new,courier;\">memory_order_consume, memory_order_acquire, memory_order_release <span style=\"font-family: arial,helvetica,sans-serif;\">and<\/span> memory_order_acq_rel<\/span><\/li>\n<li><strong>Relaxed<\/strong>: <span style=\"font-family: courier new,courier;\">memory_order_relaxed<\/span><\/li>\n<\/ul>\n<p>While the sequential consistency establishes a global order between threads, the acquire-release semantic establishes an ordering between reading and write operations on the same atomic variable on different threads. The relaxed semantic only guarantees that operations on the same atomic data type in the same thread can not be reordered. That guarantee is called <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/atomic\/memory_order\">modification order consistency.<\/a> But other threads can see this operation in a different order.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>Admit, that was a short post. But I will stick to my idea of discussing only one topic in one post.<\/p>\n<p>Especially the levels of the different memory models and their effects on atomic and non-atomic operations make the C++ memory model a thrilling but also challenging topic. In the next post, I will discuss sequential consistency&#8217;s synchronization and ordering constraints, the acquire-release semantic, and the relaxed semantic. I will do it in theory and practice. The<a href=\"https:\/\/www.modernescpp.com\/index.php\/sequential-consistency-applied\"> following post <\/a>with be about the application of sequential consistency. The base is laid out in the post <a href=\"https:\/\/www.modernescpp.com\/index.php\/sequential-consistency\">sequential consistency.<\/a><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post, our tour through the c++ memory model goes one step deeper. Until now, the posts were only about the atomicity of the atomic data types, but&nbsp;now we deal with the synchronization and ordering constraints of the operations.<\/p>\n","protected":false},"author":21,"featured_media":4798,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[368],"tags":[505,434,523,504,519],"class_list":["post-4799","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","tag-relaxed-semantics","tag-sequential-consistency"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4799","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=4799"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4799\/revisions"}],"predecessor-version":[{"id":6968,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4799\/revisions\/6968"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/4798"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=4799"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=4799"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=4799"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}