{"id":11023,"date":"2011-04-06T07:00:00","date_gmt":"2011-04-06T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/04\/06\/lock-free-algorithms-the-singleton-constructor\/"},"modified":"2011-04-06T07:00:00","modified_gmt":"2011-04-06T07:00:00","slug":"lock-free-algorithms-the-singleton-constructor","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20110406-00\/?p=11023","title":{"rendered":"Lock-free algorithms: The singleton constructor"},"content":{"rendered":"<p>\nThe first half may be familiar to many (most?) readers,\nbut there&#8217;s an interesting exercise at the bottom.\n<\/p>\n<p>\nA very useful pattern for the Interlocked* functions is\nlock-free lazy initialization via\n<code>Interlocked&shy;Compare&shy;Exchange&shy;Pointer&shy;Release<\/code>.\nYes, that&#8217;s a really long function name, but it turns out\nevery part of it important.\n<\/p>\n<pre>\nWidget *g_pwidCached;\nWidget *GetSingletonWidget()\n{\n Widget *pwid = g_pwidCached;\n if (!pwid) {\n  pwid = new(nothrow) Widget();\n  if (pwid) {\n   Widget *pwidOld = reinterpret_cast&lt;Widget*&gt;\n       (InterlockedCompareExchangePointerRelease(\n          &amp;reinterpret_cast&lt;PVOID&amp;&gt;(g_pwidCached),\n          pwid, NULL));\n   if (pwidOld) {\n    delete pwid; \/\/ lost the race - destroy the redundant copy\n    pwid = pwidOld; \/\/ use the old one\n   }\n  }\n }\n return pwid;\n}\n<\/pre>\n<p>\nThis is a double-check lock, but without the locking.\nInstead of taking lock when doing the initial construction,\nwe just let it be a free-for-all over who gets to create the\nobject.\nIf five threads all reach this code at the same time,\nsure, let&#8217;s create five objects.\nAfter everybody creates what they think is the winning object,\nthey called\n<code>Interlocked&shy;Compare&shy;Exchange&shy;Pointer&shy;Release<\/code>\nto attempt to update the global pointer.\n<\/p>\n<p>\nThe parts of the name of the\n<code>Interlocked&shy;Compare&shy;Exchange&shy;Pointer&shy;Release<\/code>\nfunction\nwork like this:\n<\/p>\n<ul>\n<li><code>Interlocked<\/code>: The operation is atomic.\n    This is important to avoid two threads successfully updating\n    the value of <code>g_pwidCached<\/code>.\n<\/li>\n<li><code>Compare<\/code>: The value in <code>g_pwidCached<\/code>\n    is compared against <code>NULL<\/code>.\n<\/li>\n<li><code>Exchange<\/code>:\n    If the values are equal, then\n    <code>g_pwidCached<\/code> is set to <code>pwid<\/code>.\n    This, combined with the comparison, ensures that only one\n    thread gets to set the value of <code>g_pwidCached<\/code>.\n<\/li>\n<li><code>Pointer<\/code>:\n    The operations are on pointer-sized data.\n<\/li>\n<li><code>Release<\/code>:\n    The operation takes place with\n    <a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2008\/10\/03\/8969397.aspx\">\n    release semantics<\/a>.\n    This is important to ensure that the <code>pwid<\/code> we created\n    is fully-constructed before we publish its pointer to other\n    processors.\n<\/li>\n<\/ul>\n<p>\nThis technique is suitable when it&#8217;s okay to let multiple threads\ntry to create the singleton (and have all the losers destroy\ntheir copy).\nIf creating the singleton is expensive or has unwanted\nside-effects, then you don&#8217;t want to use the free-for-all algorithm.\n<\/p>\n<p>\nBonus reading:\n<\/p>\n<ul>\n<li>\n    <a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa363808.aspx\">\n    One-Time Initialization<\/a>\n    helper functions save you from having to write all this code\n    yourself.\n    They deal with all the synchronization and memory barrier\n    issues, and support both the one-person-gets-to-initialize\n    and the free-for-all-initialization models.\n<\/li>\n<li>\n    <a HREF=\"http:\/\/www.bluebytesoftware.com\/blog\/2007\/06\/09\/ALazyInitializationPrimitiveForNET.aspx\">\n    A lazy initialization primitive for .NET<\/a>\n    provides a C# version of the same.\n<\/li>\n<\/ul>\n<p>\nOkay, now here&#8217;s the interesting exercise.\nThis is an actual problem I helped out with,\nalthough details have been changed for expository purposes.\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\nWe have a data structure which manages a bunch of singleton objects,\nlet&#8217;s say that they are instances of a structure\ncalled <code>ITEMCONTROLLER<\/code> and they are keyed by a 32-bit ID.\nWe&#8217;re looking for design suggestions on making it thread-safe.\nThe existing code goes like this (pseudocode):\n<\/p>\n<pre>\nstruct ITEMCONTROLLER;\nstruct SINGLETONINFO {\n DWORD dwId;\n ITEMCONTROLLER *(*pfnCreateController)();\n};\nclass SingletonManager {\npublic:\n \/\/ rgsi is an array that describes how to create the objects.\n \/\/ It's a static array, with csi in the range 20 to 50.\n SingletonManager(const SINGLETONINFO *rgsi, UINT csi)\n               : m_rgsi(rgsi), m_csi(csi),\n                 m_rgcs(NULL), m_ccs(0), m_ccsAlloc(0) { }\n ~SingletonManager() { ... }\n ITEMCONTROLLER *Lookup(DWORD dwId);\nprivate:\n struct CREATEDSINGLETON {\n  DWORD dwId;\n  ITEMCONTROLLER *pic;\n };\nprivate:\n const SINGLETONINFO *m_rgsi;\n int m_csi;\n \/\/ Array that describes objects we've created\n CREATEDSINGLETON *m_rgcs;\n int m_ccs;\n};\nITEMCONTROLLER *SingletonManager::Lookup(DWORD dwId)\n{\n int i;\n \/\/ See if we already created one\n for (i = 0; i &lt; m_ccs; i++) {\n  if (m_rgcs[i].dwId == dwId)\n   return m_rgcs[i].pic;\n }\n \/\/ Not yet created - time to create one\n ITEMCONTROLLER *pic;\n for (i = 0; i &lt; m_rgsi; i++) {\n  if (m_rgsi[i].dwId == dwId) {\n   pic = m_rgsi[i].pfnCreateController();\n   break;\n  }\n }\n if (pic == NULL) return;\n ... if m_rgcs == NULL then allocate it and update m_ccsAlloc\n ... else realloc it bigger and update m_ccsAlloc\n \/\/ append to our array so we can find it next time\n m_rgcs[m_ccs].dwId = dwId;\n m_rgcs[m_ccs].pic  = pic;\n m_ccs++;\n return pic;\n}\n<\/pre>\n<p>\nIn words, the <code>SingletonManager<\/code> takes an array\nof <code>SINGLETONINFO<\/code> structures, each of which\ncontains an ID and a function to call to create the object\nwith that ID.\nTo look up an entry, we first check if we already created one;\nif so, then we just return the existing one.\nOtherwise, we create the object (using <code>pfnCreateController<\/code>)\nand add it to our array of created objects.\n<\/p>\n<p>\nOur initial inclination is to put a critical section around\nthe entire <code>Lookup<\/code> function, but maybe there&#8217;s\nsomething more clever we can do here.\nMaybe a\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa904937.aspx\">\nslim reader-writer lock<\/a>?\n<\/p>\n<\/blockquote>\n<p>\n<b>Bonus chatter<\/b>:\nAlthough it&#8217;s the case on Windows that\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2008\/10\/03\/8969397.aspx\">\nthe plain versions of the interlocked functions impose both acquire\nand release semantics<\/a>,\nother platforms may not follow Windows&#8217; lead.\nIn particular,\non the XBOX360 platform, the plain versions of the interlocked\nfunctions impose <u>neither<\/u> acquire nor release semantics.\nI don&#8217;t know what the rules are for Windows CE.\n<\/p>\n<p>\n<b>Erratum<\/b>:\nI once knew but subsequently forgot that the\nsingleton pattern described in this article\n(with the <code>InterlockedCompareExchangePointer<\/code>)\nis\n<a HREF=\"http:\/\/www.cs.umd.edu\/~pugh\/java\/memoryModel\/AlphaReordering.html\">\nnot safe on some CPU architectures<\/a>.\nAn additional <code>MemoryBarrier()<\/code> needs to be inserted\nafter the fetch of the single pointer to ensure that indirections\nthrough it will retrieve the new values and not any cached old values:\n<\/p>\n<pre>\nWidget *GetSingletonWidget()\n{\n Widget *pwid = g_pwidCached;\n if (!pwid) {\n  ...\n } <font COLOR=\"blue\">else {\n  \/\/ Ensure that dereferences of pwid access new values and not old\n  \/\/ cached values.\n  MemoryBarrier();<\/font>\n }\n return pwid;\n}\n<\/pre>\n<p>\nThe discussion of lock-free algorithms continues\n(with probably more errors!) next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The first half may be familiar to many (most?) readers, but there&#8217;s an interesting exercise at the bottom. A very useful pattern for the Interlocked* functions is lock-free lazy initialization via Interlocked&shy;Compare&shy;Exchange&shy;Pointer&shy;Release. Yes, that&#8217;s a really long function name, but it turns out every part of it important. Widget *g_pwidCached; Widget *GetSingletonWidget() { Widget *pwid [&hellip;]<\/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-11023","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The first half may be familiar to many (most?) readers, but there&#8217;s an interesting exercise at the bottom. A very useful pattern for the Interlocked* functions is lock-free lazy initialization via Interlocked&shy;Compare&shy;Exchange&shy;Pointer&shy;Release. Yes, that&#8217;s a really long function name, but it turns out every part of it important. Widget *g_pwidCached; Widget *GetSingletonWidget() { Widget *pwid [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/11023","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=11023"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/11023\/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=11023"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=11023"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=11023"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}