{"id":34843,"date":"2005-07-22T10:00:15","date_gmt":"2005-07-22T10:00:15","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/07\/22\/the-importance-of-passing-the-wt_executelongfunction-flag-to-queueuserworkitem\/"},"modified":"2005-07-22T10:00:15","modified_gmt":"2005-07-22T10:00:15","slug":"the-importance-of-passing-the-wt_executelongfunction-flag-to-queueuserworkitem","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050722-15\/?p=34843","title":{"rendered":"The importance of passing the WT_EXECUTELONGFUNCTION flag to QueueUserWorkItem"},"content":{"rendered":"<p><P>\nOne of the flags to\n<A HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/dllproc\/base\/queueuserworkitem.asp\">\nthe <CODE>QueueUserWorkItem<\/CODE> function<\/a>\nis\n<CODE>WT_EXECUTELONGFUNCTION<\/CODE>.\nThe documentation for that flag reads\n<\/P>\n<BLOCKQUOTE CLASS=\"q\">\nThe callback function can perform a long wait.\nThis flag helps the system to decide if it should create a new thread.\n<\/BLOCKQUOTE>\n<P>\nAs noted in the documentation, the\n<A HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/dllproc\/base\/thread_pooling.asp\">\nthread pool<\/A>\nuses this flag to decide whether\nit should create a new thread or wait for an existing work item to finish.\nIf all the current thread pool threads are busy running work items and there\nis another work item to dispatch,\nit will tend to wait for one of the existing work items to complete\nif they are &#8220;short&#8221;,\nbecause the expectation is that some work item will finish quickly\nand its thread will become available to run a new work item.\nOn the other hand, if the work items are marked\n<CODE>WT_EXECUTELONGFUNCTION<\/CODE>,\nthen the thread pool\nknows that waiting for the running work item to complete is\nnot going to be very productive, so it is more likely to create\na new thread.\n<\/P>\n<P>\nIf you fail to mark a long work item with the\n<CODE>WT_EXECUTELONGFUNCTION<\/CODE> flag,\nthen the thread pool ends up waiting for that work item to\ncomplete, when it really should be kicking off a new thread.\nEventually, the thread pool gets impatient and figures out that\nyou lied to it, and it creates a new thread anyway.\nBut it often takes a while before the thread pool realizes\nthat it&#8217;s been waiting in vain.\n<\/P>\n<P>\nLet&#8217;s illustrate this with a simple console program.\n<\/P>\n<PRE>\n#include &lt;windows.h&gt;\n#include &lt;stdio.h&gt;<\/p>\n<p>DWORD g_dwLastTick;<\/p>\n<p>void CALLBACK Tick(void *, BOOLEAN)\n{\n DWORD dwTick = GetTickCount();\n printf(&#8220;%5d\\n&#8221;, dwTick &#8211; g_dwLastTick);\n}<\/p>\n<p>DWORD CALLBACK Clog(void *)\n{\n Sleep(4000);\n return 0;\n}<\/p>\n<p>int __cdecl\nmain(int argc, char* argv[])\n{\n g_dwLastTick = GetTickCount();\n switch (argc) {\n case 2: QueueUserWorkItem(Clog, NULL, 0); break;\n case 3: QueueUserWorkItem(Clog, NULL, WT_EXECUTELONGFUNCTION); break;\n }\n HANDLE hTimer;\n CreateTimerQueueTimer(&amp;hTimer, NULL, Tick, NULL, 250, 250, 0);\n Sleep(INFINITE);\n return 0;\n}\n<\/PRE>\n<P>\nThis program creates a periodic thread pool work item that fires\nevery 250ms, and which merely prints how much time has elapsed since\nthe timer was started.\nAs a baseline, run the program with no parameters, and observe that\nthe callbacks occur at roughly 250ms intervals, as expected.\n<\/P>\n<PRE>\n  251\n  501\n  751\n 1012\n^C\n<\/PRE>\n<P>\nNext, run the program with a single command line parameter.\nThis causes the &#8220;case 2&#8221; to be taken, where the &#8220;Clog&#8221; work item\nis queued.  The &#8220;Clog&#8221; does what its names does: It clogs up the\nwork item queue by taking a long time (four seconds) to complete.\nNotice that the first callback doesn&#8217;t occur for a whole\nsecond.\n<\/P>\n<PRE>\n 1001\n 1011\n 1021\n 1021\n 1252\n 1502\n 1752\n^C\n<\/PRE>\n<P>\nThat&#8217;s because we queued the &#8220;Clog&#8221; work item without the\n<CODE>WT_EXECUTELONGFUNCTION<\/CODE> flag.\nIn other words, we told the thread pool,\n&#8220;Oh, don&#8217;t worry about this guy, he&#8217;ll be finished soon.&#8221;\nThe thread pool wanted to run the Tick event,\nand since the Clog work item was marked as &#8220;fast&#8221;,\nthe thread pool decided to wait for it and recycle its thread\nrather than create a new one.\nAfter about a second,\nthe thread pool got impatient and spun up a new thread to\nservice the now-long-overdue Tick events.\n<\/P>\n<P>\nNotice that as soon as the first Tick event was processed,\nthree more were fired in rapid succession.\nThat&#8217;s because the thread pool realized that it had fallen\nfour events behind (thanks to the clog) and had to fire\nthe next three immediately just to clear its backlog.\nThe fifth and subsequent events fire roughly on time\nbecause the thread pool has figured out that the Clog really\nis a clog and should be treated as a long-running event.\n<\/P>\n<P>\nFinally, run the program with two command line parameters.\nThis causes the &#8220;case 3&#8221; to be taken, where we queue up the Clog\nbut also pass the <CODE>WT_EXECUTELONGFUNCTION<\/CODE> flag.\n<\/P>\n<PRE>\n  251\n  511\n  761\n 1012\n^C\n<\/PRE>\n<P>\nNotice that with this hint, the thread pool no longer gets\nfooled by the Clog and knows to spin up a new thread to handle\nthe Tick events.\n<\/P>\n<P>\nMoral of the story:\nIf you&#8217;re going to go wading into the thread pool,\nmake sure you play friendly with other kids and let the\nthread pool know ahead of time whether\nyou&#8217;re going to take a long time.\nThis allows the thread pool to keep the number of worker\nthreads low (thus reaping the benefits of thread pooling)\nwhile still creating enough threads to keep the events flowing\nsmoothly.\n<\/P>\n<P>\nExercise: What are the consequences to the thread pool if\nyou create a thread pool timer whose callback takes longer\nto complete than its timer period?\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the flags to the QueueUserWorkItem function is WT_EXECUTELONGFUNCTION. The documentation for that flag reads The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread. As noted in the documentation, the thread pool uses this flag to decide whether it should create [&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-34843","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>One of the flags to the QueueUserWorkItem function is WT_EXECUTELONGFUNCTION. The documentation for that flag reads The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread. As noted in the documentation, the thread pool uses this flag to decide whether it should create [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/34843","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=34843"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/34843\/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=34843"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=34843"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=34843"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}