{"id":97115,"date":"2017-09-29T07:00:00","date_gmt":"2017-09-29T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=97115"},"modified":"2019-03-13T01:17:39","modified_gmt":"2019-03-13T08:17:39","slug":"20170929-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170929-00\/?p=97115","title":{"rendered":"Why does my thread handle suddenly go bad? All I did was wait on it!"},"content":{"rendered":"<p>A customer reported that they had a very strange bug, where waiting on a thread handle causes it to become invalid. Here&#8217;s a code fragment: <\/p>\n<pre>\nDWORD waitResult = WaitForSingleObject(hThread, INFINITE);\nassert(waitResult == WAIT_OBJECT_0); \/\/ assertion passes\n\nDoSomeCleanup();\n\nCloseHandle(hThread);\n<\/pre>\n<p>That final call to <code>Close&shy;Handle<\/code> results in a <code>STATUS_<\/code><code>INVALID_<\/code><code>HANDLE<\/code> exception when run in the debugger. How did the handle become invalid? We sucessfully waited on it just a few lines earlier. <\/p>\n<p>There wasn&#8217;t enough information to go on, so we had to make some guesses. Perhaps <code>hThread<\/code> was already closed, and it got recycled to refer to some unrelated kernel object, and it&#8217;s that unrelated object that you&#8217;re waiting on when you call <code>Wait&shy;For&shy;Single&shy;Object<\/code>. And then when you do some cleanup, that causes the unrelated handle to be closed, which means that the numeric value of <code>hThread<\/code> now refers to an invalid handle. <\/p>\n<p>The customer did some investigation and discovered that they were obtaining the thread handle from the <a HREF=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/c-runtime-library\/reference\/beginthread-beginthreadex\"><code>_begin&shy;thread<\/code> function<\/a>. The handle returned by the <code>_begin&shy;thread<\/code> function is explicitly documented as being closed by the <code>_end&shy;thread<\/code> function. <\/p>\n<blockquote CLASS=\"q\"><p><code>_end&shy;thread<\/code> automatically closes the thread handle, whereas <code>_end&shy;thread&shy;ex<\/code> does not. Therefore, when you use <code>_begin&shy;thread<\/code> and <code>_end&shy;thread<\/code>, do not explicitly close the thread handle by calling the Win32 <code>Close&shy;Handle<\/code> API. This behavior differs from the Win32 <code>Exit&shy;Thread<\/code> API.  <\/p><\/blockquote>\n<p>Basically, the deal is that the <code>_begin&shy;thread<\/code> function returns a handle to the created thread, but does not give you ownership of the handle. Ownership of that handle remains with the thread itself, and the thread automatically closes the handle when it exits. (Not mentioned in the MSDN documentation for <code>_begin&shy;thread<\/code> is that the runtime automatically calls <code>_end&shy;thread<\/code> if the thread function returns normally. This detail is mentioned <a HREF=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/c-runtime-library\/reference\/endthread-endthreadex\">in the documentation for <code>_end&shy;thread<\/code><\/a>, which is probably a better place for it anyway.) <\/p>\n<p>Basically, the handle returned by the <code>_begin&shy;thread<\/code> function is useless. You don&#8217;t know how long it&#8217;s valid, and it might even be invalid by the time you even receive it! <\/p>\n<p>Switching to <code>_end&shy;thread&shy;ex<\/code> fixed the problem. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>The scary world of _beginthread.<\/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-97115","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The scary world of _beginthread.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/97115","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=97115"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/97115\/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=97115"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=97115"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=97115"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}