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 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 The reason for this can be gleaned from the (Larry Osterman reminded me that he covered the same topic a while back. So now you get to see it twice.) |
Comments (14)
Comments are closed. |
If you never want to wait for all handles, then why was the option ever specified in the first place?
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"?
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.
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.
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.)
…
Oh, yeah, that would be an option, wouldn’t it. Heh. So much for that then.
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.
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…
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.)
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.
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.
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.
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 :)