{"id":10873,"date":"2011-04-20T07:00:00","date_gmt":"2011-04-20T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/04\/20\/corrections-to-patterns-for-using-the-initonce-functions\/"},"modified":"2011-04-20T07:00:00","modified_gmt":"2011-04-20T07:00:00","slug":"corrections-to-patterns-for-using-the-initonce-functions","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20110420-00\/?p=10873","title":{"rendered":"Corrections to Patterns for using the InitOnce functions"},"content":{"rendered":"<p>\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/04\/08\/10151258.aspx#10151421\">\nAdam Rosenfield pointed out<\/a>\nthat it is not possible to fail an\nasynchronous initialization;\nif you pass\n<code>INIT_ONCE_INIT_FAILED<\/code>\nwhen completing an asynchronous initialization,\nthe function fails with\n<code>ERROR_INVALID_PARAMETER<\/code>.\n(Serves me right for writing an article the night before it goes up.)\nA more correct version is therefore\n<\/p>\n<pre>\nITEMCONTROLLER *SingletonManager::Lookup(DWORD dwId)\n{\n ... same as before until we reach the \"singleton constructor pattern\"\n void *pv = NULL;\n BOOL fPending;\n if (!InitOnceBeginInitialize(&amp;m_rgio[i], INIT_ONCE_ASYNC,\n                              &amp;fPending, &amp;pv)) return NULL;\n if (fPending) {\n  ITEMCONTROLLER *pic = m_rgsi[i].pfnCreateController();\n  <font COLOR=\"blue\">if (!pic) return NULL;\n  if (InitOnceComplete(&amp;m_rgio[i], INIT_ONCE_ASYNC, pic)) {<\/font>\n   pv = pic;\n  } else {\n   \/\/ lost the race - discard ours and retrieve the winner\n   delete pic;\n   InitOnceBeginInitialize(&amp;m_rgio[i], INIT_ONCE_CHECK_ONLY,\n                           X&amp;fPending, &amp;pv);\n  }\n }\n return static_cast&lt;ITEMCONTROLLER *&gt;(pv);\n}\n<\/pre>\n<p>\nIn other words, the pattern is as follows:\n<\/p>\n<ul>\n<li>Call <code>Init&shy;Once&shy;Begin&shy;Initialize<\/code>\n    in async mode.\n<\/li>\n<li>If it returns <code>fPending == FALSE<\/code>,\n    then initialization has already been performed and you can\n    go ahead and use the result passed back in the final parameter.\n<\/li>\n<li>Otherwise, initialization is pending.\n    Do your initialization, but remember that since this is a lock-free\n    algorithm, there can be many threads trying to initialize\n    simultaneously, so you have to be careful\n    <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/04\/07\/10150728.aspx\">\n    how you manipulate global state<\/a>.\n    This pattern works best if initialization takes the form of\n    creating a new object (because that means multiple threads\n    performining initialization are each creating independent objects).\n<\/li>\n<li><font COLOR=\"blue\">If initialization fails, then abandon the operation.<\/font>\n<\/li>\n<li>Call <code>Init&shy;Once&shy;Complete<\/code> with the result\n    of your initialization.\n<\/li>\n<li>If <code>Init&shy;Once&shy;Complete<\/code> succeeds,\n    then you won the initialization race, and you&#8217;re done.\n<\/li>\n<li>If <code>Init&shy;Once&shy;Complete<\/code> fails,\n    then you lost the initialization race and should clean up your\n    failed initialization.\n    In that case, you should call\n    <code>Init&shy;Once&shy;Begin&shy;Initialize<\/code>\n    one last time to get the answer from the winner.\n<\/li>\n<\/ul>\n<p>\nWhile I&#8217;m here, I may as well answer the exercises.\n<\/p>\n<p>\n<b>Exercise<\/b>: Instead of calling\n<code>Init&shy;Once&shy;Complete<\/code> with\n<code>INIT_ONCE_INIT_FAILED<\/code>,\nwhat happens if the function simply returns\nwithout ever completing the init-once?\n<\/p>\n<p>\n<b>Answer<\/b>: The <code>INIT_ONCE<\/code> structure is left\nin an <i>asynchronous initialization pending<\/i> state.\nThis is fine, because the next attempt to initialize will simply\njoin the race.\n(And it will win since we already quit the race!)\n<\/p>\n<p>\n<b>Exercise<\/b>:\nWhat happens if two threads try to perform\nasynchronous initialization and the first one\nto complete fails?\n<\/p>\n<p>\n<b>Answer<\/b>:\nIf two threads both begin initialization and the first one to\ncome to a result concludes that the initialization fails, then\nit will abandon the initialization.\nThe second thread will then come to its own conclusion.\nIf that conclusion is also failure, then it too will\nabandon the initialization as well.\nIf that conclusion is that initialization was successful,\nthen its completion will succeed and the <code>INIT_ONCE<\/code>\nwill enter the <i>initialized<\/i> state.\n<\/p>\n<p>\n<b>Exercise<\/b>:\nCombine the results of the first two exercises\nand draw a conclusion.\n<\/p>\n<p>\n<b>Answer<\/b>:\nIt is fine to abandon a failed initialization (and indeed,\ngiven what we learned above, it is indeed mandatory).\n<\/p>\n<p>\nThere is a documentation update coming soon to clarify that\nyou cannot combine\n<code>INIT_ONCE_ASYNC<\/code> and\n<code>INIT_ONCE_INIT_FAILED<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Adam Rosenfield pointed out that it is not possible to fail an asynchronous initialization; if you pass INIT_ONCE_INIT_FAILED when completing an asynchronous initialization, the function fails with ERROR_INVALID_PARAMETER. (Serves me right for writing an article the night before it goes up.) A more correct version is therefore ITEMCONTROLLER *SingletonManager::Lookup(DWORD dwId) { &#8230; same as before [&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-10873","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Adam Rosenfield pointed out that it is not possible to fail an asynchronous initialization; if you pass INIT_ONCE_INIT_FAILED when completing an asynchronous initialization, the function fails with ERROR_INVALID_PARAMETER. (Serves me right for writing an article the night before it goes up.) A more correct version is therefore ITEMCONTROLLER *SingletonManager::Lookup(DWORD dwId) { &#8230; same as before [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/10873","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=10873"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/10873\/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=10873"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=10873"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=10873"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}