{"id":97405,"date":"2017-11-15T07:00:00","date_gmt":"2017-11-15T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=97405"},"modified":"2019-03-13T01:20:21","modified_gmt":"2019-03-13T08:20:21","slug":"20171115-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20171115-00\/?p=97405","title":{"rendered":"What happens if you simply return from the thread callback passed to _beginthread and _beginthreadex?"},"content":{"rendered":"<p>Medinoc asks, &#8220;<a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20170929-00\/?p=97115#comment-1310746\">What happens when one simply returns from the thread callback<\/a>? I&#8217;d suspect the code gluing between _beginthread() and its callback calls _endthread() upon return, while the code between _beginthreadex() and its callback calls _endthreadex() instead?&#8221; <\/p>\n<p>Yup, that&#8217;s exactly it. If your thread callback function returns, then <code>_begin&shy;thread<\/code> calls <code>_end&shy;thread<\/code> on your behalf, and then <code>_begin&shy;thread&shy;ex<\/code> calls <code>_end&shy;thread&shy;ex<\/code> on your behalf. The value passed to <code>_end&shy;thread&shy;ex<\/code> is the return value of your thread callback function. <\/p>\n<p>In response to the remark &#8220;beginthread() initializes the CRT,&#8221; Cesar asked, &#8220;<a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20170929-00\/?p=97115#comment-1310785\">Which CRT<\/a>? A process can have more than one CRT, and the thread function can even call functions from several different C runtimes.&#8221; <\/p>\n<p>The <code>_begin&shy;thread<\/code> function initializes the CRT it belongs to. What other choice does it have? It&#8217;s not like <code>msvcr80!<\/code><code>_beginthread<\/code> knows how to initialize the data used by <code>msvcr90.dll<\/code>. If you call <code>msvcr80!<\/code><code>_beginthread<\/code>, then the new thread is initialized for the <code>msvcr80<\/code> runtime, since that&#8217;s the only one it knows about. <\/p>\n<p>If the thread function calls into multiple C runtimes, then that&#8217;s its decision. If it calls into a C runtime that hasn&#8217;t been initialized for that thread, then what happens next depends on the behavior of that C runtime. For quite some time now, Microsoft&#8217;s C runtimes <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20170929-00\/?p=97115#comment-1310795\">are self-initializing<\/a>, meaning that the first time you call into them on a thread, they will initialize themselves on the spot. And they will also auto-uninitialize themselves when the thread exits. <\/p>\n<p>Wait, if the C runtime initializes itself on demand and auto-uninitializes, then why bother with <code>_beginthread<\/code> at all? <\/p>\n<p>Well, the functions are still around because they predated the initialize-on-demand and auto-uninitialize behavior. And they do guarantee that the C runtime will be initialized for the new thread. (If not, then the functions return failure.) If you go for the initialize-on-demand case, and the C runtime cannot initialize itself, then something interesting happens. <\/p>\n<ul>\n<li>    Some functions will handle the case where the C runtime failed     to initialize in some way.     for example,     <code>_tempnam<\/code> and <code>strerror<\/code>     will return <code>NULL<\/code> to report a failure.     (Sometimes this failure mode is documented; sometimes it isn&#8217;t.)     Other functions will fall back to a static buffer     instead of a per-thread buffer. <\/li>\n<li>    Other functions will exit the process with the error message     &#8220;<tt>R6016 - not enough space for thread data<\/tt>.&#8221; <\/li>\n<\/ul>\n<p>But as Harry Johnston noted, &#8220;In practice very few applications will survive running out of memory anyway.&#8221; <\/p>\n<p>Joshua Shaeffer asks, &#8220;<a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20170929-00\/?p=97115#comment-1310825\">Instead of automatically closing the handle, how about automatically never opening the handle<\/a>?&#8221; <\/p>\n<p>Not sure what Joshua is trying to say here, because the C runtime didn&#8217;t open the handle. The handle was created by the operating system and returned by the <code>Create&shy;Thread<\/code> function. So the C runtime really doesn&#8217;t have a choice. The handle gets opened as part of the thread-creation process. All it can do is decide what to do with the handle once it is given one. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Who&#8217;s got the thread handle?<\/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-97405","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Who&#8217;s got the thread handle?<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/97405","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=97405"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/97405\/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=97405"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=97405"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=97405"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}