{"id":94995,"date":"2016-12-22T07:00:00","date_gmt":"2016-12-22T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=94995"},"modified":"2019-03-13T10:35:05","modified_gmt":"2019-03-13T17:35:05","slug":"20161222-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20161222-00\/?p=94995","title":{"rendered":"Another pattern for using the InitOnce functions"},"content":{"rendered":"<p>In my survey of <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20110408-01\/?p=10983\">patterns for using the InitOnce functions<\/a>, I omitted the synchronous two-phase initialization. <\/p>\n<p>The synchronous two-phase initialization is similar to the simple callback-based version in that only one thread gets to attempt an initialization at a time. But instead of doing the initialization in a callback, you do the initialization inline. <\/p>\n<p>As a refresher, here&#8217;s how you do it using <code>Init&shy;Once&shy;Execute&shy;Once<\/code>: <\/p>\n<pre>\nBOOL CALLBACK AllocateAndInitializeTheThing(\n    PINIT_ONCE initOnce,\n    PVOID parameter,\n    PVOID *context)\n{\n    *context = new(std::nothrow) Thing();\n    return *context != nullptr;\n}\n\nThing *GetSingletonThing()\n{\n    static INIT_ONCE initOnce = INIT_ONCE_STATIC_INIT;\n    void *result;\n    if (InitOnceExecuteOnce(&amp;initOnce,\n                            AllocateAndInitializeTheThing,\n                            nullptr, &amp;result)) {\n        return static_cast&lt;Thing*&gt;(result);\n    }\n    return nullptr;\n}\n<\/pre>\n<p>To use <code>Init&shy;Once&shy;Begin&shy;Initialize<\/code> in synchronous mode, you basically move the callback function inline: <\/p>\n<pre>\nThing *GetSingletonThing()\n{\n    static INIT_ONCE initOnce = INIT_ONCE_STATIC_INIT;\n    void *result;\n    BOOL pending;\n    if (InitOnceBeginInitialize(&amp;initOnce, 0,\n                                &amp;pending, &amp;result)) {\n        if (pending) {\n            \/\/ Try to initialize the thing.\n            result = new(std::nothrow) Thing();\n\n            InitOnceComplete(&amp;initOnce,\n                result ? 0 : INIT_ONCE_INIT_FAILED,\n                result);\n        }\n        return static_cast&lt;Thing*&gt;(result);\n    }\n    return nullptr;\n}\n<\/pre>\n<p>You start by calling <code>Init&shy;Once&shy;Begin&shy;Initialize<\/code>, and the value stored in the <code>pending<\/code> parameter tells you whether you need to run the initialization. If it says that you need to initialize, then do your initialization and then report the result back by calling <code>Init&shy;Once&shy;Complete<\/code>, saying either <code>0<\/code> to mean that initialization succeeded, or <code>INIT_ONCE_INIT_FAILED<\/code> to say that it failed. <\/p>\n<p>If a second thread tries to initialize while an initialization is already in progress, the initial request waits to see what the result of the existing initialization is. If the existing initialization eventually succeeds, then the second initialization is told, &#8220;It&#8217;s all good. No need to initialize.&#8221; If the existing initialization eventually fails, then the second initialization is told, &#8220;Not yet initialized. Why don&#8217;t you give it a shot?&#8221; <\/p>\n<p>In other words, <code>Init&shy;Once&shy;Execute&shy;Once<\/code> acts like a wrapper that goes roughly like this: <\/p>\n<pre>\nBOOL InitOnceExecuteOnce(\n    PINIT_ONCE initOnce,\n    PINIT_ONCE_FN callback,\n    void* parameter,\n    void** context)\n{\n  BOOL pending;\n  BOOL success = InitOnceBeginInitialize(\n                          initOnce, 0, &amp;pending, context)) {\n  if (success) {\n    if (pending) {\n      success = callback(initOnce, parameter, context);\n      InitOnceComplete(initOnce,\n        success ? 0 : INIT_ONCE_INIT_FAILED, *context);\n    }\n  }\n  return success;\n}\n<\/pre>\n<p>Here&#8217;s a comparison table: <\/p>\n<table BORDER=\"1\" STYLE=\"border-collapse: collapse\" CELLSPACING=\"0\" CELLPADDING=\"3\">\n<tr>\n<td><\/td>\n<th>    Init&shy;Once&shy;Execute&shy;Once     <\/th>\n<th>    Init&shy;Once&shy;Begin&shy;Initialize<br>    Synchronous mode     <\/th>\n<th>    Init&shy;Once&shy;Begin&shy;Initialize<br>    Asynchronous mode     <\/th>\n<\/tr>\n<tr>\n<td>How initialized<\/td>\n<td>Callback<\/td>\n<td>Inline<\/td>\n<td>Inline<\/td>\n<\/tr>\n<tr>\n<td>Initialization parallelism<\/td>\n<td>Serialized<\/td>\n<td>Serialized<\/td>\n<td>Parallel<\/td>\n<\/tr>\n<tr>\n<td>Success reporting<\/td>\n<td>Callback returns TRUE<\/td>\n<td>Init&shy;Once&shy;Complete(0)<\/td>\n<td>Init&shy;Once&shy;Complete(INIT_ONCE_ASYNC)<\/td>\n<\/tr>\n<tr>\n<td>Failure reporting<\/td>\n<td>Callback returns FALSE<\/td>\n<td>Init&shy;Once&shy;Complete(INIT_ONCE_FAILED)<\/td>\n<td>Do nothing<\/td>\n<\/tr>\n<\/table>\n","protected":false},"excerpt":{"rendered":"<p>The synchronous two-phase initialization.<\/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-94995","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The synchronous two-phase initialization.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/94995","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=94995"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/94995\/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=94995"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=94995"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=94995"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}