{"id":95485,"date":"2017-02-20T07:00:00","date_gmt":"2017-02-20T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=95485"},"modified":"2019-03-13T01:06:31","modified_gmt":"2019-03-13T08:06:31","slug":"20170220-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170220-00\/?p=95485","title":{"rendered":"Another more efficient solution to the problem of a long-running task running on the thread pool persistent thread"},"content":{"rendered":"<p><a HREF=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/\">Last time<\/a>, we broke up a series of operations on the persistent thread pool thread so that the thread pool did the waiting rather then clogging up the persistent thread with a synchronous wait. This does still have the downside of processing the notification on the persistent thread, which could be a problem if that processing is time-consuming. <\/p>\n<p>What we can do is to use the persistent thread pool thread only for things that absolutely must be done on a persistent thread, and move everything else to a thread pool task thread. <\/p>\n<p>Make the highlighted changes to the code we had from last time.<\/p>\n<pre>\n\/\/ Error checking elided for expository purposes.\n\nvoid WidgetMonitor::RegisterNotificationWait(\n <font COLOR=\"blue\">void* parameter<\/font>)\n{\n <font COLOR=\"blue\">WidgetNotificationContext* context =\n   reinterpret_cast&lt;WidgetNotificationContext*&gt;(parameter);<\/font>\n RegisterWaitForSingleObject(&amp;context-&gt;waitHandle,\n  context-&gt;registryEvent,\n  WidgetNotificationWaitCallback,\n  context,\n  INFINITE,\n  WT_EXECUTEONLYONCE <font COLOR=\"red\"><strike>\/* | WT_EXECUTEINPERSISTENTTHREAD *\/<\/strike><\/font>);\n RegNotifyChangeKeyValue(context-&gt;hkey, false,\n                         REG_NOTIFY_CHANGE_LAST_SET,\n                         context-&gt;registryEvent, TRUE);\n}\n\nvoid WidgetMonitor::WidgetNotificationWaitCallback(\n    void* parameter, BOOLEAN \/* TimerOrWaitFired *\/)\n{\n WidgetNotificationContext* context =\n   reinterpret_cast&lt;WidgetNotificationContext*&gt;(parameter);\n\n ... process the change ...\n\n <font COLOR=\"blue\">QueueUserWorkItem(RegisterNotificationWait,\n                   context,\n                   WT_EXECUTEINPERSISTENTTHREAD);<\/font>\n}\n\nvoid WidgetMonitor::StartMonitoring()\n{\n auto context = new WidgetNotificationContext();\n <font COLOR=\"blue\">context-&gt;hkey = ...;\n context-&gt;registryEvent = ...;<\/font>\n QueueUserWorkItem(<font COLOR=\"blue\">RegisterNotificationWait<\/font>,\n                   context,\n                   WT_EXECUTEINPERSISTENTTHREAD);\n}\n\nvoid WidgetMonitor::StopMonitoring(\n    WidgetNotificationContext* context)\n{\n \/\/ WARNING! Massive race conditions here need to be addressed.\n\n if (context-&gt;waitHandle) {\n  UnregisterWait(context-&gt;waitHandle);\n  context-&gt;waitHandle = nullptr;\n }\n ... clean up other resources ...\n delete context;\n}\n<\/pre>\n<p>What we did this time was to put only the <code>Reg&shy;Notify&shy;Change&shy;key&shy;Value<\/code> on the persistent thread. Everything else runs on a normal thread pool thread. That way, we minimize the amount of code running on the persistent thread. <\/p>\n<p>The last fix we can make is to take advantage of a new feature in Windows 8: The <code>REG_NOTIFY_THREAD_AGNOSTIC<\/code> flag, which turns off the old behavior of stopping the notification when the thread exits. With that change, we don&#8217;t need the <code>WT_EXECUTE&shy;IN&shy;PERSISTENT&shy;THREAD<\/code> flag at all. <\/p>\n<pre>\n\/\/ Error checking elided for expository purposes.\n\nvoid WidgetMonitor::RegisterNotificationWait(\n WidgetNotificationContext* context)\n{\n RegisterWaitForSingleObject(&amp;context-&gt;waitHandle,\n  context-&gt;registryEvent,\n  WidgetNotificationWaitCallback,\n  context,\n  INFINITE,\n  WT_EXECUTEONLYONCE <font COLOR=\"red\"><strike>\/* | WT_EXECUTEINPERSISTENTTHREAD *\/<\/strike><\/font>);\n RegNotifyChangeKeyValue(context-&gt;hkey, false,\n                         REG_NOTIFY_CHANGE_LAST_SET |\n                         <font COLOR=\"blue\">REG_NOTIFY_THREAD_AGNOSTIC<\/font>,\n                         context-&gt;registryEvent, TRUE);\n}\n\nvoid WidgetMonitor::WidgetNotificationWaitCallback(\n    void* parameter, BOOLEAN \/* TimerOrWaitFired *\/)\n{\n WidgetNotificationContext* context =\n   reinterpret_cast&lt;WidgetNotificationContext*&gt;(parameter);\n\n ... process the change ...\n\n RegisterNotificationWait(context);\n}\n\nvoid WidgetMonitor::StartMonitoring()\n{\n auto context = new WidgetNotificationContext();\n <font COLOR=\"blue\">context-&gt;hkey = ...;\n context-&gt;registryEvent = ...;<\/font>\n RegisterNotificationWait(context);\n}\n\nvoid WidgetMonitor::StopMonitoring(\n    WidgetNotificationContext* context)\n{\n \/\/ WARNING! Massive race conditions here need to be addressed.\n\n if (context-&gt;waitHandle) {\n  UnregisterWait(context-&gt;waitHandle);\n  context-&gt;waitHandle = nullptr;\n }\n ... clean up other resources ...\n delete context;\n}\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The thread-agnostic change notification.<\/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-95485","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The thread-agnostic change notification.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/95485","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=95485"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/95485\/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=95485"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=95485"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=95485"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}