Home
About
Blog
Media Gallery

PeekMessage loops for realtime programs


Good. Handles the entire pump every main loop iteration.
while(1) {

	// Håndter systemmeldinger til vinduet, diskré.
	while (PeekMessage(&Msg, 0, 0, 0, PM_REMOVE) != 0) {
		TranslateMessage(&Msg);
		DispatchMessage(&Msg);
	} 

	// Avslutt hvis WM_QUIT har blitt postet.
	if (Msg.message == WM_QUIT)
		break;

	// Oppdater projisering og musebehandling.
	DoStuff();

	// CPU vennlig.
	Sleep(10);
}
return (int)Msg.wParam;


Bad. May try to DoStuff() after DestroyWindow in WNDPROC has been called, since it only polls a single message per iteration and may not discover WM_QUIT in time. This results in the program and its threads returning 1 to the system instead of a clean 0 (successful exit).
do {
	// Håndter systemmeldinger til vinduet, diskré.
	if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE) != 0) {
		TranslateMessage(&Msg);
		DispatchMessage(&Msg);
	} 

	// Oppdater projisering og musebehandling.
	DoStuff(); 

	// CPU vennlig.
	Sleep(10);

} while (Msg.message != WM_QUIT);
return (int)Msg.wParam;




Additional information

Interesting quotes from the 2001 MS KnowledgeBase Article Q74042:

NOTE: The PeekMessage method described in this article is only needed if your
application is a 32-bit application for Windows and is, for some reason, unable
to create threads and perform background processing.

...

Remaining in a PeekMessage() loop when there is no background work causes system
performance problems. A program in a PeekMessage() loop continues to be
rescheduled by the Windows scheduler, consuming CPU time and taking time away
from other processes.

...

Many power management methods employed on laptop and notebook computers are based
on the system going idle when there is no processing to do. An application that
remains in a PeekMessage() loop will make the system appear busy to power
management software, resulting in excessive power consumption and shortening the
time that the user can run the system.

...

In the future, the Windows system will make more and more use of idle time to do
background processing, which is designed to optimize system performance.
Applications that do not allow the system to go idle will adversely affect the
performance of these techniques.

All these problems can be avoided by calling the PeekMessage() function only when
there is background work to do, and calling GetMessage() or WaitMessage() when
there is no background work to do.



The information above suggests that it's preferable to just use the default GetMessage() which is pre-coded in most modern Win32 application templates, like in VS2022:
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}


And do your main loop or background work in a separate thread. Or, if still using PeekMessage, block the loop with WaitMessage(), illustrated by MS like so:
for(;;)
{
	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
	{
		if (msg.message == WM_QUIT)
			return TRUE;

		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	if (IfBackgroundProcessingRequired())
		BackgroundProcessing();
	else
		WaitMessage(); // Will not return until a message is posted.
}


Personally, I'd lean towards leaving the message loop alone (using a default GetMessage() one) and do my main loop work in separate thread(s); avoiding any possible overhead of polling messages unnecessarily as well as it affecting the main loop performance in any way at all.

Original Post: Sep 20th, '22 13:43 CEST.
Updated: Sep 21st, '22 13:07 CEST.

Tags: C/C++