{"id":10760,"date":"2025-05-19T09:11:18","date_gmt":"2025-05-19T09:11:18","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=10760"},"modified":"2025-05-19T09:11:18","modified_gmt":"2025-05-19T09:11:18","slug":"atomicshared_ptr-by-oliver-schadlich","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/atomicshared_ptr-by-oliver-schadlich\/","title":{"rendered":"atomic&lt;shared_ptr&lt;>> by Oliver Sch\u00e4dlich"},"content":{"rendered":"\n<p>This blog article is an experiment. A few days ago, I received the following email (translated from German) from Oliver Sch\u00e4dlich (oliver.schaedlich@gmail.com). If, as I hope, this article sparks a discussion, I will be happy to summarize it in my last article.<br><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"963\" height=\"392\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/TimelineCpp20CoreLanguage.png\" alt=\"\" class=\"wp-image-10761\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/TimelineCpp20CoreLanguage.png 963w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/TimelineCpp20CoreLanguage-300x122.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/TimelineCpp20CoreLanguage-768x313.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/TimelineCpp20CoreLanguage-705x287.png 705w\" sizes=\"auto, (max-width: 963px) 100vw, 963px\" \/><\/figure>\n\n\n\n<p>Please send an email to: <a href=\"mailto:Rainer.Grimm@ModernesCpp.de\">Rainer.Grimm@ModernesCpp.de<\/a>.<\/p>\n\n\n\n<p><em>I just read your latest article on hazard pointers with a look at RCU on Heise. Inspired by YouTube presentations on lock-free variants of atomic&lt;shared_ptr&lt;&gt;&gt;, I thought to myself: it doesn&#8217;t have to be that complicated. In principle, you could implement something like an atomic&lt;shared_ptr&lt;&gt;&gt; simply with Lock, and when updating the shared_ptr&lt;&gt; from the central atomic&lt;shared_ptr&lt;&gt;&gt;, a comparison of the atomic with the shared_ptr is first performed without locking.<\/em><\/p>\n\n\n\n<p><em>Usually, with RCU-like patterns with a central \u201catomic&lt;shared_ptr&lt;&gt;&gt;,\u201d this is updated relatively rarely, but you very often fetch an update of the current value. Normally, if both pointers point to the same thing, you simply don&#8217;t lock, and you get a super-fast update because all cache lines involved remain shared.<\/em><\/p>\n\n\n\n<p><em>I implemented this rudimentarily with VS 2022, and updating the shared_obj&lt;T&gt; from the central tshared_obj&lt;&gt; takes about 1.5 nanoseconds on my Zen4 CPU. The solution is so simple that I wondered why no one had thought of it before.<\/em><\/p>\n\n\n\n<p><em>In principle, you could give the shared_ptr&lt;&gt; from C++ an assignment operator that takes an atomic&lt;shared_ptr&lt;&gt;&gt; that does the same thing. Currently, the atomic&lt;shared_ptr&lt;&gt;&gt; casts to shared_ptr&lt;&gt; and a relatively expensive copy is performed. libstdc++ and MSVC currently work with a lock at this point, which would still not be a problem if you proceed as described for the special case in question. Perhaps you could pass the idea on to the appropriate place so that something like this can be included in one of the next standards.<\/em><br><\/p>\n\n\n\n<p>Here is the code that Oliver Sch\u00e4dlich sent me. It is written in C++20 and uses the standard library. The files are<code> futex.cpp, main.cpp, cl_size.h, futex.h, <\/code>and <code>shared_obj.h<\/code>.<\/p>\n\n\n\n<p>You can download the source code here: <a href=\"https:\/\/www.dropbox.com\/scl\/fi\/ea8hi6dk7e7b4loao4mja\/source.7z?rlkey=l5dsdxpd6lol25wdd3iksv0ei&amp;st=x040bzba&amp;dl=0\">source.7z.<\/a><\/p>\n\n\n\n<p>The most interesting file is <code>shared_obj.h<\/code> and the following function within it:<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #006699; font-weight: bold\">template<\/span><span style=\"color: #555555\">&lt;<\/span><span style=\"color: #006699; font-weight: bold\">typename<\/span> T<span style=\"color: #555555\">&gt;<\/span>\nshared_obj<span style=\"color: #555555\">&lt;<\/span>T<span style=\"color: #555555\">&gt;<\/span> <span style=\"color: #555555\">&amp;<\/span>shared_obj<span style=\"color: #555555\">&lt;<\/span>T<span style=\"color: #555555\">&gt;::<\/span><span style=\"color: #006699; font-weight: bold\">operator<\/span> <span style=\"color: #555555\">=<\/span>( tshared_obj<span style=\"color: #555555\">&lt;<\/span>T<span style=\"color: #555555\">&gt;<\/span> <span style=\"color: #006699; font-weight: bold\">const<\/span> <span style=\"color: #555555\">&amp;<\/span>tso ) noexcept\n{\n\t<span style=\"color: #006699; font-weight: bold\">using<\/span> <span style=\"color: #006699; font-weight: bold\">namespace<\/span> std;\n\t<span style=\"color: #007788; font-weight: bold\">ctrl_t<\/span> <span style=\"color: #555555\">*<\/span>ctrl <span style=\"color: #555555\">=<\/span> tso.m_ctrl.load( memory_order_relaxed );\n\t<span style=\"color: #006699; font-weight: bold\">if<\/span>( ctrl <span style=\"color: #555555\">==<\/span> m_ctrl )\n\t\t<span style=\"color: #006699; font-weight: bold\">return<\/span> <span style=\"color: #555555\">*<\/span><span style=\"color: #006699; font-weight: bold\">this<\/span>;\n\t<span style=\"color: #006699; font-weight: bold\">if<\/span>( m_ctrl )\n\t{\n\t\t<span style=\"color: #006699; font-weight: bold\">if<\/span>( m_ctrl<span style=\"color: #555555\">-&gt;<\/span>decr() <span style=\"color: #555555\">==<\/span> <span style=\"color: #FF6600\">1<\/span> )\n\t\t\t<span style=\"color: #006699; font-weight: bold\">delete<\/span> m_ctrl;\n\t\tm_ctrl <span style=\"color: #555555\">=<\/span> nullptr;\n\t}\n\tlock_guard<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #006699; font-weight: bold\">typename<\/span> tshared_obj<span style=\"color: #555555\">&lt;<\/span>T<span style=\"color: #555555\">&gt;::<\/span><span style=\"color: #007788; font-weight: bold\">mutex_t<\/span><span style=\"color: #555555\">&gt;<\/span> lock( tso.m_mtx );\n\tctrl <span style=\"color: #555555\">=<\/span> tso.m_ctrl.load( memory_order_relaxed );\n\tm_ctrl <span style=\"color: #555555\">=<\/span> ctrl;\n\tctrl<span style=\"color: #555555\">-&gt;<\/span>incr();\n\t<span style=\"color: #006699; font-weight: bold\">return<\/span> <span style=\"color: #555555\">*<\/span><span style=\"color: #006699; font-weight: bold\">this<\/span>;\n}\n<\/pre><\/div>\n\n\n\n<p><em>If I remove the first if with return *this, the code is a few thousand times slower, about as slow as updating a shared_ptr&lt;> from an atomic&lt;shared_ptr&lt;>>.<\/em><br><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What&#8217;s next?<\/h2>\n\n\n\n<p>RCU stands for Read Copy Update, a synchronization technique for almost exclusively read-only data structures developed by Paul McKenney and used in the Linux kernel since 2002. RCU is currently mentioned in connection with hazard pointers.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This blog article is an experiment. A few days ago, I received the following email (translated from German) from Oliver Sch\u00e4dlich (oliver.schaedlich@gmail.com). If, as I hope, this article sparks a discussion, I will be happy to summarize it in my last article. Please send an email to: Rainer.Grimm@ModernesCpp.de. I just read your latest article on [&hellip;]<\/p>\n","protected":false},"author":21,"featured_media":10761,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[],"class_list":["post-10760","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10760","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=10760"}],"version-history":[{"count":3,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10760\/revisions"}],"predecessor-version":[{"id":10764,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10760\/revisions\/10764"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/10761"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=10760"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=10760"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=10760"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}