Waiting for all handles with MsgWaitForMultipleObjects is a bug waiting to happen

Date:January 27, 2006 / year-entry #37
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20060127-17/?p=32493
Comments:    14
Summary:The MsgWaitForMultipleObjects and MsgWaitForMultipleObjectsEx functions allow you to specify whether you want to want for any or all of the handles (either by passing bWaitAll = TRUE or by passing dwFlags = MWMO_WAITALL, accordingly). But you never want to wait for all handles. Waiting for all handles means that the call does not return unless...

The MsgWaitForMultipleObjects and MsgWaitForMultipleObjectsEx functions allow you to specify whether you want to want for any or all of the handles (either by passing bWaitAll = TRUE or by passing dwFlags = MWMO_WAITALL, accordingly). But you never want to wait for all handles.

Waiting for all handles means that the call does not return unless all the handles are signalled and a window message meeting your wake criteria has arrived. Since you are typically waiting for messages out of a sense of obligation (keeping the UI thread responsive) rather than one of expectation, even if all the handles you pass become signalled, your program will still stall until a window message arrives. (And if you thought you were being a good UI citizen by using MsgWaitForMultipleObjectsEx, you aren't actually helping any because waiting for all objects means that the call will not return even if a message is ready, since it's also waiting for those handles you passed.) Functions which are built on top of the MsgWaitForMultipleObjectsEx function such as MsgWaitForMultipleObjects and CoWaitForMultipleHandles suffer from the same problem.

The reason for this can be gleaned from the MsgWaitForMultipleObjectsEx documentation; you just have to put on your thinking cap. Notice that if a message arrives when you are waiting for any handle, the return value is WAIT_OBJECT_0 + cHandles. Notice also that the maximum number of objects you can wait on is MAXIMUM_WAIT_OBJECTS - 1. Obviously, what's happening under the covers is that the MsgWaitForMultipleObjectsEx function creates a handle that will be signalled when the message queue reaches one of the states you requested in the wake mask, adds that handle to the end of the array you passed in, and then passes the whole thing to the WaitForMultipleObjectsEx function. (Note that the getting access to that internal handle won't be of any use to you, the application, since you don't know how to tell the window manager what wait states should result in the event being set.)

(Larry Osterman reminded me that he covered the same topic a while back. So now you get to see it twice.)


Comments (14)
  1. Neil says:

    If you never want to wait for all handles, then why was the option ever specified in the first place?

  2. Good Point says:

    The latest documentation is pretty clear. Under dwWakeMask it says "Input types for which an input event object handle will be added to the array of object handles"

    Now, how does one go about creating an "input event object handle"?

  3. Neil: Probably because somebody said, "We should expose all the functionality of WaitForMultipleObjects – otherwise I’m sure somebody will complain that we hid the functionality for some evil purpose."

    GP: You don’t create the event object handle; the window manager does.

  4. Jerry Pisk says:

    Waiting on a UI thread is a problem no mater what you do. If you need to wait for something then fire off a thread to do that. UI thread should be handling UI events, not waiting for some background processing to finish.

  5. BryanK says:

    Jerry — so what do you do when you have to wait until the thread that you fired off finishes?

    (Not just a thread to wait for something else, but think about a thread doing a bunch of CPU intensive work.)

  6. Pavel Lebedinsky says:

    what do you do when you have to wait until the thread that you fired off finishes?

    The worker thread could post a "finished" message to the UI thread.

  7. BryanK says:

    Oh, yeah, that would be an option, wouldn’t it. Heh. So much for that then.

  8. bmm6o says:

    BrianK: I agree. The docs as quoted by Larry are pretty clear. I could see how a casual reader could miss it though, especially as it seems much more useful for the function to return when all passed in handles are signalled OR there is a new message.

  9. Tim Lesher says:

    BrianK: not to split hairs, but the post says "The reason for this can be gleaned from the MsgWaitForMultipleObjectsEx documentation; you just have to put on your thinking cap."

    It doesn’t say "the fact that this happens can be gleaned…". If it did, I’d agree with you. No, you don’t need to think about the implementation. But Raymond’s saying that if you care about the implementation, with a tiny bit of thought you can figure it out.

    Nothing personal, but I always get a bad feeling from programmers who automatically trust the documentation and assume it tells them everything they need to know, and that they never need to think about the implementation or read between the lines.

    Or maybe I’ve just been programming Windows too long…

  10. BryanK says:

    Er, hang on a minute…

    > The reason for this can be gleaned from the

    > MsgWaitForMultipleObjectsEx documentation; you

    > just have to put on your thinking cap.

    I think you just have to read carefully. Note the documentation’s description of bWaitAll (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/msgwaitformultipleobjects.asp):

    ——–

    bWaitAll

    If this parameter is TRUE, the function returns when the states of all objects in the pHandles array have been set to signaled *and an input event has been received*.

    ——–

    (Emphasis mine.)

    This is explicit enough to tell me that it will wait until a message comes in *AND* all the handles are signaled. I don’t need to think about the implementation, I just need to read the description of the parameter and notice the difference between it and WaitForMultipleObjects.

    Larry, if you’re reading this, your post has the same issue. You even quote the MSDN doc page on MsgWaitForMultipleObjects (the text I’ve quoted above), and you say that it’s "the same as WaitForMultipleObjects" — but it isn’t. The WaitForMultipleObjects page says:

    ——–

    bWaitAll

    If this parameter is TRUE, the function returns when the state of all objects in the lpHandles array is signaled.

    ——–

    Perhaps this used to be an issue in the documentation or something, I don’t know. But it’s not an issue anymore — if people are still doing this, it has to be because they either can’t or won’t read the docs, not because there’s some deep thinking that they have to do.

    (Unless I misunderstand what an "input event" is. That’s always possible.)

  11. Chris Smith says:

    I can think of a reason to use MsgWaitForMultipleObjects with bWaitAll set to true: if you are waiting for a non-gui message, like a socket message from WSAAsyncSelect, or a background timer message.

    Your thread could be waiting for an event from an overlapped file operation, a mutex lock, and a socket select (delivered by msg) to be ready at the same time.

  12. Gideon says:

    Even with bWaitAll=FALSE there is (or was) a well-known problem with starvation. The kernel checks the event array sequentially. So basically if Handle[n] is constantly tripping it can starve all the handles > n.

    I noticed it when writing an NT network server application. The lowest numbered socket got serviced while the higher number sockets timed out. Investigation revealed that the select() Winsock API was calling MsgWaitForMultipleObjects().

    I dunno if they fixed it since NT.

  13. BryanK says:

    I was trying to say that I’m not so sure anything has to be "gleaned" — it’s pretty obvious just reading the bWaitAll docs.

  14. Mark Steward says:

    Gideon: surely by definition select returns all sockets that are ready? I admittedly don’t have experience of early NT, but it seems a major bug if it only returns one. And if simply doesn’t bother to check the entire set *after* calling MsgWaitForMultipleObjects, the next call to select would catch any others.

    But anyway, MsgWaitForMultipleObjects is documented as only returning the first handle in the array. "If multiple objects become signaled, the function returns the index of the first handle in the array whose object was signaled." I think this is something you have to program around :)

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index