According to here, GetMessage()
is a blocking call which won't return until there's a message can be retrieved from the message queue.
So, how is this blocking behavior implemented?
Does GetMessage()
use some kind of spin lock so that the UI thread just busy waits for new messages showing up in the message queue? If so, I guess at least one of my CPU cores should have high usage when a UI application is running. But I didn't see that happen. So how does it work?
ADD 1
Thanks for the hint in the comments. Spin lock is meant to reduce the cost of thread context switch. It shouldn't be used here. I also thought about maybe some event paradigm is used here. But if it is event-driven, how does this event model work?
My guess is like this:
- An event for input checking is raised periodically. Perhaps via some hardware timer interrupt. Then the timer interrupt handler will check for various input device buffers for input events. And then put that into certain application's message queue based on the current desktop context, such as which is the active window.
And I guess maybe some other things are also based on the timer interrupt, such as thread context switching.
ADD 2
Based on replies so far. There's some event object that the UI thread waits on. But since UI thread is waiting on something, it is not active and can do nothing by itself yet. And the event object is just some passive state information. So there has to be someone else to wake up the thread upon the event state change. I tink it should be the thread scheduler. And the thread scheduler may be pulsed by the timer interrupt.
The thread scheduler will check the event state periodically and wake up thread and put messages into its queue as necessary.
Am I right about the whole picture?
ADD 3
And there's a remaining question: who modify the state of an event object? Based on here, it seems events are just some data structures that can be modified by any active parties. I think thread scheduler just use the relations among threads and events to decide which thread to run or not.
And by the time a thread is scheduled to run, all it's requirements should already been fulfilled. Such as a message should have been put into its queue before the event it waits on is raised. This is reasonable because otherwise it may be too late. (thanks to RbMm's comments.)
ADD 4
In JDK, the LinkedBlockingDeque type also offers a similar blocking behavior with the take()
method.
Retrieves and removes the head of the queue represented by this deque (in other words, the first element of this deque), waiting if necessary until an element becomes available.
And the .NET counterpart is the BlockingCollection< T > type. A thread to discuss it.
Here is a thread about how to implement a blocking queue in C#.