{"id":110169,"date":"2024-08-23T07:00:00","date_gmt":"2024-08-23T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110169"},"modified":"2024-08-23T08:57:55","modified_gmt":"2024-08-23T15:57:55","slug":"20240823-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240823-00\/?p=110169","title":{"rendered":"What if I need to wait for more than <CODE>MAXIMUM_<WBR>WAIT_<WBR>OBJECTS<\/CODE> threads?"},"content":{"rendered":"<p>A customer had a test that created a lot of threads, and they wanted their test to wait for all of the threads to exit before proceeding to the next step. However, the number of threads exceeded the maximum number of handles, more than <code>MAXIMUM_<wbr \/>WAIT_<wbr \/>OBJECTS<\/code> of them, so what is the best way to wait for all of them if they can&#8217;t do a single <code>Wait\u00adFor\u00adMultiple\u00adObjects<\/code>?<\/p>\n<p>The customer noted that the documentation had a few suggestions. One is to divide the objects into groups of size at most <code>MAXIMUM_<wbr \/>WAIT_<wbr \/>OBJECTS<\/code> and for each group, create a thread to call <code>Wait\u00adFor\u00adMultiple\u00adObjects<\/code>. Another suggestion is to call <code>Register\u00adWait\u00adFor\u00adSingle\u00adObject<\/code> on each handle.<\/p>\n<p>The customer thought these approaches were unnecessarily complicated. What about just dividing the objects into groups of size at most <code>MAXIMUM_<wbr \/>WAIT_<wbr \/>OBJECTS<\/code> and just going into a loop calling <code>Wait\u00adFor\u00adMultiple\u00adObjects<\/code> on each group? &#8220;Is there some subtlety that we&#8217;re missing?&#8221;<\/p>\n<p>Process handles and thread handles have the property that waits on them are idempotent. Waiting on a process or thread handle waits for the process or thread to exit, but it has no effect on the process or thread itself. This is different from some other types of handles: Waiting on semaphores, mutexes, and auto-reset events has side effects: Consuming a semaphore token, taking ownership of the mutex, and resetting an auto-reset event.<\/p>\n<p>Furthermore, process and thread handles also have the property that once they become signaled, they never become unsignaled. This means that once you have successfully waited on them to become signaled, you don&#8217;t have to worry about the possibility that in the future, they might not be signaled any more.<\/p>\n<p>Therefore, if you are waiting for a group of process and thread handles all to be signaled, you have the liberty to wait for them in any order and not require the special behavior of <code>Wait\u00adFor\u00adMultiple\u00adObjects<\/code> where it doesn&#8217;t create any wait side-effects until all the objects become signaled simultaneously.<\/p>\n<p>So yes, you can wait for them in blocks of <code>MAXIMUM_<wbr \/>WAIT_<wbr \/>OBJECTS<\/code>. But really, even that is too much work. You can just wait for them one at a time.<\/p>\n<pre>for (auto&amp;&amp; handle : m_threadHandles)\r\n{\r\n    REQUIRE(WaitForSingleObject(handle, INFINITE)\r\n            == WAIT_OBJECT_0);\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Studying your options, and the consequences of breaking things up.<\/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-110169","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Studying your options, and the consequences of breaking things up.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110169","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=110169"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110169\/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=110169"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110169"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110169"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}