{"id":3483,"date":"2013-08-16T07:00:00","date_gmt":"2013-08-16T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/08\/16\/if-i-signal-an-auto-reset-event-and-there-is-a-thread-waiting-on-it-is-it-guaranteed-that-the-event-will-be-reset-and-the-waiting-thread-released-before-setevent-returns\/"},"modified":"2013-08-16T07:00:00","modified_gmt":"2013-08-16T07:00:00","slug":"if-i-signal-an-auto-reset-event-and-there-is-a-thread-waiting-on-it-is-it-guaranteed-that-the-event-will-be-reset-and-the-waiting-thread-released-before-setevent-returns","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130816-00\/?p=3483","title":{"rendered":"If I signal an auto-reset event and there is a thread waiting on it, is it guaranteed that the event will be reset and the waiting thread released before SetEvent returns?"},"content":{"rendered":"<p>\nLet&#8217;s go straight to the question:\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\nI have two programs that take turns doing something.\nRight now, I manage the hand-off with two auto-reset events.\nIn Thread&nbsp;A,\nafter it finishes doing some work, it\nsignals Event&nbsp;B and then immediately waits on\nEvent&nbsp;A.\nThread&nbsp;B does the converse:\nWhen its wait on Event&nbsp;B completes, it does some work,\nthen signals Event&nbsp;A and then immediately waits\non Event&nbsp;B.\n<\/p>\n<p>\nThis works great, but I&#8217;m wondering if I can save myself\nan event and use the same event to hand control back and forth.\nIs it guaranteed that when Thread&nbsp;A signals Event&nbsp;B,\nthat this will release Thread&nbsp;B and reset the event\n(since it is auto-reset) before the call to\n<code>Set&shy;Event<\/code> returns?\nIf so, then I can just have one event and use it to bounce\ncontrol back and forth.\n<\/p>\n<\/blockquote>\n<p>\nLet&#8217;s try it!\n<\/p>\n<pre>\n<i>#include &lt;windows.h&gt;\n#include &lt;stdio.h&gt;\nHANDLE h;\nDWORD CALLBACK ThreadProc(void *msg)\n{\n for (;;) {\n  SetEvent(h);\n  \/\/ The theory is that the above SetEvent does not return\n  \/\/ until the other thread has positively completed its wait,\n  \/\/ so this upcoming wait will not complete until the other\n  \/\/ thread calls SetEvent.\n  WaitForSingleObject(h, INFINITE);\n  puts((LPSTR)msg);\n }\n}\nint __cdecl main(int, char**)\n{\n DWORD id;\n h = CreateEvent(0, FALSE, TRUE, 0);\n CloseHandle(CreateThread(0, 0, ThreadProc, \"T1\", 0, &amp;id));\n CloseHandle(CreateThread(0, 0, ThreadProc, \"T2\", 0, &amp;id));\n Sleep(INFINITE);\n return 0;\n}\n<\/i><\/pre>\n<p>\nIf you run this program,\nyou&#8217;ll see that the two threads come nowhere near taking turns.\nInstead, you see stretches where\nthread&nbsp;T1 gets to run a whole bunch of iterations\nin a row, and stretches where\nthread&nbsp;T2 gets to run a whole bunch of iterations in a row.\n<\/p>\n<p>\nOkay, so we have demonstrated by experiment that this technique\ndoes not work.\n(You can use experimentation to show that something doesn&#8217;t always work,\nbut you can&#8217;t use it to show that something always <i>will<\/i> work.\nFor that you need to read some contracts and put on your thinking\ncap.)\nBut why doesn&#8217;t it work?\n<\/p>\n<p>\nThe lawyerly explanation for why it doesn&#8217;t work is that there\nis nothing in the contract that says that it <i>does<\/i> work.\nPerfectly correct, but not particularly insightful.\n<\/p>\n<p>\nSignaling an event makes all waiting threads eligible to run,\nbut that doesn&#8217;t mean that they actually <i>will<\/i> run.\nOne of the waiting threads is woken to say\n&#8220;Hey, now&#8217;s your chance.&#8221;\nBut that thread might be groggy and slow to wake,\nand in the meantime, another thread can swoop in and steal the event signal.\nAnd then that groggy thread shuffles downstairs to the breakfast\ntable to find that somebody ate his pancake.\n(Actually, in principle, the kernel could just make it a total free-for-all\nand wake <i>all<\/i> the waiting threads, but I suspect it just picks one.)\n<\/p>\n<p>\nWe saw earlier that the thread that you would expect to run next\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2005\/01\/05\/346888.aspx\">\nmight be temporarily unavailable and miss its chance to claim\nwhat it thinks is rightfully his<\/a>.\nAnd more recent versions of Windows have exacerbated the problem\nby\n<a HREF=\"http:\/\/www.bluebytesoftware.com\/blog\/PermaLink,guid,e40c2675-43a3-410f-8f85-616ef7b031aa.aspx\">\nabandoning fairness<\/a>\nin order to improve throughput\nand avoid lock convoys.\nNow, in principle, the kernel could have reset the event when it woke\nthe waiting thread, thereby assigning the wake to the thread at signal time,\nbut that would have reintroduced the problem that unfairness was trying to\nsolve.\n<\/p>\n<p>\nThe irony here is that what you&#8217;re doing here is\nintentionally trying to <i>create<\/i> a convoy,\nand you&#8217;re running into the scheduler&#8217;s convoy-resistance.\n<\/p>\n<p>\nJust use the two-event pattern.\nThat makes it explicit what you want.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Let&#8217;s go straight to the question: I have two programs that take turns doing something. Right now, I manage the hand-off with two auto-reset events. In Thread&nbsp;A, after it finishes doing some work, it signals Event&nbsp;B and then immediately waits on Event&nbsp;A. Thread&nbsp;B does the converse: When its wait on Event&nbsp;B completes, it does some [&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-3483","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Let&#8217;s go straight to the question: I have two programs that take turns doing something. Right now, I manage the hand-off with two auto-reset events. In Thread&nbsp;A, after it finishes doing some work, it signals Event&nbsp;B and then immediately waits on Event&nbsp;A. Thread&nbsp;B does the converse: When its wait on Event&nbsp;B completes, it does some [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/3483","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=3483"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/3483\/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=3483"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=3483"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=3483"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}