{"id":2833,"date":"2013-10-25T07:00:00","date_gmt":"2013-10-25T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/10\/25\/my-those-threads-start-up-really-fast-nowadays\/"},"modified":"2013-10-25T07:00:00","modified_gmt":"2013-10-25T07:00:00","slug":"my-those-threads-start-up-really-fast-nowadays","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20131025-00\/?p=2833","title":{"rendered":"My, those threads start up really fast nowadays"},"content":{"rendered":"<p>\nHere&#8217;s a little puzzle\ninspired by an actual bug:\n<\/p>\n<pre>\n\/\/ global variable\nDWORD g_WorkerThreadId;\nbool IsRunningOnWorkerThread()\n{\n  return GetCurrentThreadId() == g_WorkerThreadId;\n}\nbool LaunchWorkerThread()\n{\n HANDLE hThread = CreateThread(nullptr, 0,\n                               WorkerThread,\n                               nullptr, 0,\n                               &amp;g_WorkerThreadId);\n if (hThread != nullptr) {\n   CloseHandle(hThread);\n   return true;\n }\n return false;\n}\nDWORD CALLBACK WorkerThread(void *Proc)\n{\n  \/\/ Can this assertion ever fire?\n  assert(IsRunningOnWorkerThread());\n  return 0;\n}\n<\/pre>\n<p>\nCan the assertion at the start of <code>WorkerThread<\/code>\never fire?\n<\/p>\n<p>\nNaturally, the answer is <i>Yes<\/i>,\notherwise it wouldn&#8217;t be a very interesting article.\n<\/p>\n<p>\nThe assertion can fire if the worker thread starts running\n<i>before the call the <code>Create&shy;Thread<\/code> returns<\/i>.\nIn that case, the caller hasn&#8217;t yet received the\nhandle or ID of the newly-started thread.\nThe new thread calls\n<code>Is&shy;Running&shy;On&shy;Worker&shy;Thread<\/code>,\nwhich returns <code>false<\/code> since\n<code>g_Worker&shy;Thread&shy;Id<\/code> hasn&#8217;t been initialized yet.\n<\/p>\n<p>\nThe actual bug was something along the lines of this:\n<\/p>\n<pre>\nvoid DoSomething()\n{\n  if (IsRunningOnWorkerThread()) {\n     .. do it one way ..\n  } else {\n     .. do it the other way ..\n  }\n}\nvoid DoManyThings()\n{\n  DoSomething();\n  DoSomethingElse();\n  DoYetAnotherThing();\n}\nDWORD CALLBACK WorkerThread(void *Proc)\n{\n  ...\n  DoManyThings();\n  ...\n  return 0;\n}\n<\/pre>\n<p>\nIf the new thread started up so quickly that the original thread\ndoesn&#8217;t get a chance to receive the new thread ID and put\nit into\n<code>g_Worker&shy;Thread&shy;ID<\/code>,\nthen the <code>Do&shy;Something<\/code> function\ncalled from the worker thread will accidentally do things\nthe not-on-the-worker-thread way,\nand then things start go go awry.\n<\/p>\n<p>\nOne way to address is is to add suspenders to your belt:\n<\/p>\n<pre>\nDWORD CALLBACK WorkerThread(void *Proc)\n{\n  g_WorkerThreadId = GetCurrentThreadId();\n  ...\n<\/pre>\n<p>\nBy having both the original thread and the created thread\nset the <code>g_WorkerThreadId<\/code> variable,\nyou cover both cases of the race.\nIf the original thread runs faster, then the\n<code>CreateThread<\/code> function will set the\n<code>g_WorkerThreadId<\/code> variable to the ID of the worker\nthread,\nand the first line of <code>Worker&shy;Thread<\/code>\nwill be redundant.\nOn the other hand, if the worker thread runs faster,\nthen the assignment at the beginning of\n<code>Worker&shy;Thread<\/code> sets the thread ID,\nand the assignment performed by\nthe <code>CreateThread<\/code> function will be redundant.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here&#8217;s a little puzzle inspired by an actual bug: \/\/ global variable DWORD g_WorkerThreadId; bool IsRunningOnWorkerThread() { return GetCurrentThreadId() == g_WorkerThreadId; } bool LaunchWorkerThread() { HANDLE hThread = CreateThread(nullptr, 0, WorkerThread, nullptr, 0, &amp;g_WorkerThreadId); if (hThread != nullptr) { CloseHandle(hThread); return true; } return false; } DWORD CALLBACK WorkerThread(void *Proc) { \/\/ Can this assertion [&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-2833","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Here&#8217;s a little puzzle inspired by an actual bug: \/\/ global variable DWORD g_WorkerThreadId; bool IsRunningOnWorkerThread() { return GetCurrentThreadId() == g_WorkerThreadId; } bool LaunchWorkerThread() { HANDLE hThread = CreateThread(nullptr, 0, WorkerThread, nullptr, 0, &amp;g_WorkerThreadId); if (hThread != nullptr) { CloseHandle(hThread); return true; } return false; } DWORD CALLBACK WorkerThread(void *Proc) { \/\/ Can this assertion [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/2833","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=2833"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/2833\/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=2833"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=2833"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=2833"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}