{"id":98365,"date":"2018-03-28T07:00:00","date_gmt":"2018-03-28T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=98365"},"modified":"2019-03-13T00:51:19","modified_gmt":"2019-03-13T07:51:19","slug":"20180328-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180328-00\/?p=98365","title":{"rendered":"When I memcpy a struct into a std::atomic of that struct, why does the result not match?"},"content":{"rendered":"<p>Consider the following code: <\/p>\n<pre>\n<i>\/\/ Code in italics is wrong.\n\nstruct Point3D { float x, y, z; };\n\nstd::atomic&lt;Point3D&gt; currentPoint;\n\nbool LoadCurrentPointFromFile(HANDLE file)\n{\n DWORD actualBytesRead;\n if (!ReadFile(file, &amp;currentPoint, sizeof(Point3D),\n               &amp;actualBytesRead, nullptr)) return false;\n if (actualBytesRead != sizeof(Point3D)) return false;\n return true;\n}<\/i>\n<\/pre>\n<p>This code tries to load a <code>Point3D<\/code> structure from a file directly into a <code>std::atomic<\/code>. However, the customer found that the results were not properly loaded and suspected there may a bug in the <code>Read&shy;File<\/code> function, because the value that should have been in the <code>z<\/code> member ended up in <code>y<\/code>, the value that should have been in the <code>y<\/code> member ended up in <code>x<\/code>, and the value that should have been in the <code>x<\/code> member wasn&#8217;t loaded at all. <\/p>\n<p>The <code>Read&shy;File<\/code> function is working fine. What&#8217;s wrong is that you aren&#8217;t using the <code>std::atomic<\/code> variable properly. <\/p>\n<p>The contents of a <code>std::atomic<\/code> variable are not directly accessible. You have to use methods like <code>store<\/code> and <code>load<\/code>. There are operator overloads which make atomic variables appear to be regular variables, but at no point can you get the address of the underlying <code>Point3D<\/code> storage. <\/p>\n<p>Processors have restrictions on the sizes of operands on which they can natively perform atomic operations. Some restrictions apply to the size of the operand: Most processors do not support atomic operations on 12-byte objects, and it&#8217;s not reasonable to expect a processor to be able to perform an atomic operation on a memory object that is megabytes in size, after all. Some restrictions are based on layout, such as whether the object is suitably aligned. <\/p>\n<p>In the cases where the object cannot be managed atomically by the processor, the standard library steps in and adds a lock, and operations on the atomic variable take the lock to ensure that the operation is atomic. The reason everything is shifted is that the code took the address of the atomic variable itself, which includes the intenral lock, and the value you intended to read into <code>x<\/code> didn&#8217;t vanish. It overwrote the lock! <\/p>\n<p>Access to the contents of the atomic variable must be done by the appropriate methods on the atomic variable. <\/p>\n<pre>\nbool LoadCurrentPointFromFile(HANDLE file)\n{\n DWORD actualBytesRead;\n <font COLOR=\"blue\">Point3D point;<\/font>\n if (!ReadFile(file, <font COLOR=\"blue\">&amp;point<\/font>, sizeof(Point3D),\n               &amp;actualBytesRead, nullptr)) return false;\n if (actualBytesRead != sizeof(Point3D)) return false;\n <font COLOR=\"blue\">currentPoint.store(point);<\/font>\n return true;\n}\n<\/pre>\n<p>There&#8217;s <a HREF=\"https:\/\/www.youtube.com\/watch?v=ZQFzMfHIxng\">a presentation from CppCon 2017 that covers <code>std::atomic<\/code> from start to finish<\/a>, including performance characteristics. I&#8217;m going to consider this video to be homework, because <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20180329-00\/?p=98375\">next time I&#8217;m going to chatter about it<\/a>. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>You&#8217;re storing it wrong.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-98365","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You&#8217;re storing it wrong.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/98365","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=98365"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/98365\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=98365"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=98365"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=98365"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}