{"id":19333,"date":"2009-01-29T10:00:00","date_gmt":"2009-01-29T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2009\/01\/29\/a-process-shutdown-puzzle\/"},"modified":"2009-01-29T10:00:00","modified_gmt":"2009-01-29T10:00:00","slug":"a-process-shutdown-puzzle","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20090129-00\/?p=19333","title":{"rendered":"A process shutdown puzzle"},"content":{"rendered":"<p><P>\nIn honor of National Puzzle Day,\nI leave you today with a puzzle\nbased on an actual customer problem.\n<\/P>\n<P>\n<B>Part One<\/B>: The customer explains the problem.\n<\/P>\n<BLOCKQUOTE CLASS=\"q\">\n<P>\nWe have this DLL, and during its startup, it creates a thread\nwith the following thread procedure:\n<\/P>\n<PRE>\nDWORD CALLBACK ThreadFunction(void *)\n{\n  HANDLE HandleArray[2];\n  HandleArray[0] = SetUpStuff();\n  if (HandleArray[0]) {\n    HandleArray[1] = ShutdownEvent;\n    while (WaitForMultipleObjects(2, HandleArray,\n                             FALSE, INFINITE) == WAIT_OBJECT_0) {\n      ProcessStuff();\n    }\n    CleanUpStuff(HandleArray[0]);\n  }\n  SetEvent(ThreadCompleteEvent);\n  FreeLibraryAndExitThread(ThisLibrary, 0);\n}\n<\/PRE>\n<P>\nDuring process shutdown, the following function is called\nas part of <CODE>DLL_PROCESS_DETACH<\/CODE> handling:\n<\/P>\n<PRE>\nvoid StopWorkerThread()\n{\n  \/\/ tell the thread to stop\n  SetEvent(ShutdownEvent);<\/p>\n<p>  \/\/ wait for it to stop\n  WaitForSingleObject(ThreadCompleteEvent, INFINITE);<\/p>\n<p>  \/\/ Clean up\n  CloseHandle(ShutdownEvent);\n  ShutdownEvent = NULL;<\/p>\n<p>  CloseHandle(ThreadCompleteEvent);\n  ThreadCompleteEvent = NULL;\n}\n<\/PRE>\n<P>\nThe above function is hanging at the call to\n<CODE>WaitForSingleObject<\/CODE>.\nIf we break in, we see that the thread that is supposed\nto be running the <CODE>ThreadFunction<\/CODE> is gone.\nI verified that the thread was successfully created,\nbut by the time we get around to waiting for it, it&#8217;s already gone.\n<\/P>\n<P>\nI checked, and nobody sets the <CODE>ThreadCompleteEvent<\/CODE>\nexcept the <CODE>StopWorkerThread<\/cODE> function.\nI stepped through <CODE>SetUpStuff<\/CODE>, and it succeeded.\nHowever, a breakpoint on <CODE>CleanUpStuff<\/CODE> was never hit.\nNo exceptions were thrown either.\n<\/P>\n<P>\nI am completely stumped as to how this thread disappeared.\n<\/P>\n<\/BLOCKQUOTE>\n<P>\nYou already know enough to explain how the thread disappeared.\n<\/P>\n<P>\n<B>Part Two<\/B>: After providing your explanation, the customer\ncame up with this solution.\n<\/P>\n<BLOCKQUOTE CLASS=\"q\">\n<P>\nThank you for your explanation.\nWe&#8217;ve made the following changes to fix the problem.\nAgain, thank you for your help.\n<\/P>\n<PRE>\nDWORD CALLBACK ThreadFunction(void *)\n{\n  HANDLE HandleArray[2];\n  HandleArray[0] = SetUpStuff();\n  if (HandleArray[0]) {\n    HandleArray[1] = ShutdownEvent;\n    while (WaitForMultipleObjects(2, HandleArray,\n                             FALSE, INFINITE) == WAIT_OBJECT_0) {\n      ProcessStuff();\n    }\n    CleanUpStuff(HandleArray[0]);\n  }\n  <FONT COLOR=\"blue\"><STRIKE>\/\/ SetEvent(ThreadCompleteEvent);<\/STRIKE><\/FONT>\n  FreeLibraryAndExitThread(ThisLibrary, 0);\n}<\/p>\n<p>void StopWorkerThread()\n{\n  \/\/ tell the thread to stop\n  SetEvent(ShutdownEvent);<\/p>\n<p>  \/\/ wait for <FONT COLOR=\"blue\">the thread<\/FONT>\n  WaitForSingleObject(<FONT COLOR=\"blue\">ThreadHandle<\/FONT>, INFINITE);<\/p>\n<p>  \/\/ Clean up\n  CloseHandle(ShutdownEvent);\n  ShutdownEvent = NULL;\n}\n<\/PRE>\n<\/BLOCKQUOTE>\n<P>\nCriticize this proposed solution.\n<\/P>\n<P>\n<B>Part Three<\/B>:\nEven though the proposed solution is flawed,\nexplain why it doesn&#8217;t cause a problem in practice.\n(I.e., explain why the customer is always lucky.)\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In honor of National Puzzle Day, I leave you today with a puzzle based on an actual customer problem. Part One: The customer explains the problem. We have this DLL, and during its startup, it creates a thread with the following thread procedure: DWORD CALLBACK ThreadFunction(void *) { HANDLE HandleArray[2]; HandleArray[0] = SetUpStuff(); if (HandleArray[0]) [&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-19333","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>In honor of National Puzzle Day, I leave you today with a puzzle based on an actual customer problem. Part One: The customer explains the problem. We have this DLL, and during its startup, it creates a thread with the following thread procedure: DWORD CALLBACK ThreadFunction(void *) { HANDLE HandleArray[2]; HandleArray[0] = SetUpStuff(); if (HandleArray[0]) [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/19333","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=19333"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/19333\/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=19333"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=19333"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=19333"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}