{"id":98395,"date":"2018-03-30T07:00:00","date_gmt":"2018-03-30T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=98395"},"modified":"2019-03-13T00:51:51","modified_gmt":"2019-03-13T07:51:51","slug":"20180330-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180330-00\/?p=98395","title":{"rendered":"How do I choose between the strong and weak versions of compare-exchange?"},"content":{"rendered":"<p>Last time, we left with the question of when you should prefer the strong version of compare-exchange as opposed to the weak version. <\/p>\n<p>It comes down to whether spurious failures are acceptable and how expensive they are. <\/p>\n<p>In the example given in the presentation, the cost of a spurious failure is very low: <\/p>\n<pre>\n    do { new_n-&gt;next = old_h; }\n    while (!head.compare_exchange_strong(old_h, new_n));\n<\/pre>\n<p>Recovering from a spurious failure is just updating a single variable and retrying the operation. Removing the nested loop embedded in the strong compare-exchange simplifies the outer loop. <\/p>\n<p>On the other hand, if recovering from the failure requires a lot of work, such as throwing away an object and constructing a new one, then you probably want to pay for the extra retries inside the strong compare-exchange operation in order to avoid an expensive recovery iteration. <\/p>\n<p>And of course if there is no iteration at all, then a spurious failure could be fatal. Consider <a HREF=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/\">the lock-free singleton construction pattern<\/a>: <\/p>\n<pre>\nstd::atomic&lt;Widget*&gt; cachedWidget;\n\nWidget* GetSingletonWidget()\n{\n Widget* widget = cachedWidget;\n if (!widget) {\n  widget = new(std::nothrow) Widget();\n  if (widget) {\n   Widget* previousWidget = nullptr;\n   if (!cachedWidget.compare_exchange_strong(previousWidget, widget)) {\n    \/\/ lost the race - destroy the redundant widget\n    delete widget;\n    widget = previousWidget;\n   }\n  }\n }\n return widget;\n}\n<\/pre>\n<p>If we were to switch to <code>compare_<\/code><code>exchange_<\/code><code>weak<\/code>, then a spurious failure would mean that the value of <code>cachedWidget<\/code> was <code>nullptr<\/code>, but we failed to exchange anyway. This means that we would think that we lost the race against another thread and return the <code>previousWidget<\/code> as the singleton. But in the case of a spurious failure, the <code>previousWidget<\/code> will still be <code>nullptr<\/code>, causing the code to create a Widget, think it was redundant, throw away the created Widget, and then return <code>nullptr<\/code>. This is bad news for the <code>Get&shy;Singleton&shy;Widget<\/code> function. <\/p>\n<p>Choosing between the strong and weak versions of compare-exchange requires you to understand what your algorithm does in the case of a spurious failure. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>It depends on how bad a spurious failure is for your algorithm.<\/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-98395","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It depends on how bad a spurious failure is for your algorithm.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/98395","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=98395"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/98395\/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=98395"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=98395"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=98395"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}