Reputation: 93
I am working on a home project to play with DirectX and WINAPI. I just found an interesting behavior.
In the code below, if I use my wndd->h_
(type: HWND), what was the result of CreateWindowEx()
, in the PeekMessage()
as second parameter, then the main loop starts to working on a single core with heavier load, while leaving the second parameter as 0, then the calculation spreads out well.
void WinLoop() {
while (!wndd->exit_) {
//if (PeekMessage(&(wndd->msg_), 0, 0, 0, PM_REMOVE)) { //NOTE : Frequently changing what core is loaded
if (PeekMessage(&(wndd->msg_), wndd->h_, 0, 0, PM_REMOVE)) { //NOTE : Heavy load on one core
TranslateMessage(&(wndd->msg_));
DispatchMessage(&(wndd->msg_));
}
//TODO : update
//TODO : draw
//TODO : calculate statistic
}
}
Everything seems to work just fine, but I can not find any information about this. What is under the hood?
Upvotes: 1
Views: 584
Reputation: 244732
According to the documentation for the PeekMessage
function, the second parameter is…
hWnd [in, optional]
Type: HWND
A handle to the window whose messages are to be retrieved. The window must belong to the current thread.
If hWnd is
NULL
,PeekMessage
retrieves messages for any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value isNULL
(see theMSG
structure). Therefore if hWnd isNULL
, both window messages and thread messages are processed.If hWnd is -1,
PeekMessage
retrieves only messages on the current thread's message queue whose hwnd value isNULL
, that is, thread messages as posted byPostMessage
(when the hWnd parameter isNULL
) orPostThreadMessage
.
It is also important to pay attention to what the PeekMessage
function does. In short, it retrieves the first message (matching the specified criteria, if applicable) that exists in the queue. Because you've specified the PM_REMOVE
flag, it also removes that message from the queue.
More interesting is what happens if there are no messages for you in the queue. In that case, PeekMessage
immediately returns false.
You now have enough information to understand the difference in behavior between the two function calls. In the first case, you're passing NULL
as the second parameter, so the PeekMessage
function is retrieving messages for any window that belongs to the current thread, as well as thread messages. In the second case, you're passing a handle to a specific window as the second parameter, so the PeekMessage
function is retrieving messages only for that window. Because there are a lot fewer messages to retrieve for that one window, as compared to all windows and threads, the PeekMessage
function is mostly just returning false. Little to no time is spent processing messages. And as soon as it returns false, your while
loop kicks in, looping back to the beginning and calling the PeekMessage
function again.
Basically, you've created a tight loop that just sits and burns CPU time, polling the PeekMessage
function continuously without doing anything, which interferes with the operating system's execution scheduler. The app can still get pre-empted, of course, but you are guaranteed to use 100% of your allocated time-slice.
There is a purpose for this behavior, like when writing a game. A PeekMessage
loop is also commonly used in applications that are doing lengthy background processing, but want to continue pumping messages to keep the UI responsive. But there is no reason to use PeekMessage
in a normal application's message loop where you don't need real-time processing. Instead, you want the GetMessage
function, which actually waits until it receives a message before returning. This is far more efficient in terms of CPU time because it isn't constantly polling. You get the time you need, but no more. It is also much more battery-friendly.
I assume that, if you're playing with DirectX, you probably are trying to write a game or screensaver or some other quasi-real-time thing, which is why you're using the PeekMessage
function in the first place. But you will probably want to pass NULL
as the function's second parameter, because you want to process all window and thread messages, not just the ones for your main window.
Upvotes: 2