{"id":4553,"date":"2013-04-25T07:00:00","date_gmt":"2013-04-25T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/04\/25\/if-youre-going-to-use-an-interlocked-operation-to-generate-a-unique-value-you-need-to-use-it-before-its-gone\/"},"modified":"2013-04-25T07:00:00","modified_gmt":"2013-04-25T07:00:00","slug":"if-youre-going-to-use-an-interlocked-operation-to-generate-a-unique-value-you-need-to-use-it-before-its-gone","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130425-00\/?p=4553","title":{"rendered":"If you&#8217;re going to use an interlocked operation to generate a unique value, you need to use it before it&#8217;s gone"},"content":{"rendered":"<p><P>\nIs the\n<CODE>Interlocked&shy;Increment<\/CODE> function broken?\nOne person seemed to think so.\n<\/P>\n<BLOCKQUOTE CLASS=\"q\">\n<P>\nWe&#8217;re finding that the\n<CODE>Interlocked&shy;Increment<\/CODE> is producing\nduplicate values.\nAre there are any know bugs in\n<CODE>Interlocked&shy;Increment<\/CODE>?\n<\/BLOCKQUOTE>\n<P>\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/02\/10\/10127054.aspx\">\nBecause of course when something doesn&#8217;t work,\nit&#8217;s because you are the victim of a vast conspiracy<\/A>.\nThere is a fundamental flaw in the\n<CODE>Interlocked&shy;Increment<\/CODE> function that\nonly you can see.\n<I>You are not a crackpot<\/I>.\n<\/P>\n<PRE>\nLONG g_lNextAvailableId = 0;<\/p>\n<p><I>DWORD GetNextId()\n{\n  \/\/ Increment atomically\n  InterlockedIncrement(&amp;g_lNextAvailableId);<\/p>\n<p>  \/\/ Subtract 1 from the current value to get the value\n  \/\/ before the increment occurred.\n  return (DWORD)g_lNextAvailableId &#8211; 1;\n}<\/I>\n<\/PRE>\n<P>\nRecall that\n<CODE>Interlocked&shy;Increment<\/CODE>\nfunction increments a value atomically\nand returns the incremented value.\nIf you are interested in the result of the increment,\nyou need to <I>use the return value directly<\/I>\nand not try to read the variable you incremented,\nbecause that variable may have been modified by another\nthread in the interim.\n<\/P>\n<P>\nConsider what happens when two threads call\n<CODE>Get&shy;Next&shy;Id<\/CODE>\nsimultaneously (or nearly so).\nSuppose the initial value of <CODE>g_lNext&shy;Available&shy;Id<\/CODE> is 4.\n<\/P>\n<UL>\n<LI>First thread calls\n    <CODE>Interlocked&shy;Increment<\/CODE>\n    to increment from 4 to 5.\n    The return value is 5.\n<LI>Second thread calls\n    <CODE>Interlocked&shy;Increment<\/CODE>\n    to increment from 5 to 6.\n    The return value is 6.\n<LI>First thread ignores the return value and instead\n    reads the current value of\n    <CODE>g_lNext&shy;Available&shy;Id<\/CODE>, which is 6.\n    It subtracts 1, leaving 5, and returns it.\n<LI>Second thread ignores the return value and instead\n    reads the current value of\n    <CODE>g_lNext&shy;Available&shy;Id<\/CODE>, which is still 6.\n    It subtracts 1, leaving 5, and returns it.\n<\/UL>\n<P>\nResult:\nBoth calls to\n<CODE>Get&shy;Next&shy;Id<\/CODE> return 5.\nInterpretation:\n&#8220;<CODE>Interlocked&shy;Increment<\/CODE> is broken.&#8221;\n<\/P>\n<P>\nActually,\n<CODE>Interlocked&shy;Increment<\/CODE> is working just fine.\nWhat happened is that the code threw away the unique information\nthat\n<CODE>Interlocked&shy;Increment<\/CODE> returned\nand instead went back to the shared variable,\neven though the shared variable changed its value\nin the meantime.\n<\/P>\n<P>\nSince this code cares about the result of the increment,\nit needs to use the value returned\nby <CODE>Interlocked&shy;Increment<\/CODE>.\n<\/P>\n<PRE>\nDWORD GetNextId()\n{\n  \/\/ Increment atomically and subtract 1 from the\n  \/\/ incremented value to get the value before the\n  \/\/ increment occurred.\n  return (DWORD)InterlockedIncrement(&amp;g_lNextAvailableId) &#8211; 1;\n}\n<\/PRE>\n<P>\n<B>Exercise<\/B>: Criticize this implementation of\n<CODE>IUnknown::Release<\/CODE>:\n<\/P>\n<PRE>\n<I>STDMETHODIMP_(ULONG) CObject::Release()\n{\n InterlockedDecrement(&amp;m_cRef);\n if (m_cRef == 0)\n {\n  delete this;\n  return 0;\n }\n return m_cRef;\n}<\/I>\n<\/PRE><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Is the Interlocked&shy;Increment function broken? One person seemed to think so. We&#8217;re finding that the Interlocked&shy;Increment is producing duplicate values. Are there are any know bugs in Interlocked&shy;Increment? Because of course when something doesn&#8217;t work, it&#8217;s because you are the victim of a vast conspiracy. There is a fundamental flaw in the Interlocked&shy;Increment function that [&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-4553","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Is the Interlocked&shy;Increment function broken? One person seemed to think so. We&#8217;re finding that the Interlocked&shy;Increment is producing duplicate values. Are there are any know bugs in Interlocked&shy;Increment? Because of course when something doesn&#8217;t work, it&#8217;s because you are the victim of a vast conspiracy. There is a fundamental flaw in the Interlocked&shy;Increment function that [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4553","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=4553"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4553\/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=4553"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=4553"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=4553"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}