2014
02.07

This topic seems to come up quite a lot, and yet the majority of the time, there’s no clear answer. Take the scenario: you have a game or an application, and there’s some downtime. You’ve noticed in task manager that your apps remains at a high CPU Usage% even while it’s not doing anything, and you want to reduce it somehow. Which way is best?

This is where questions like “is Sleep(0) better than Sleep(1)? How about Sleep(50)? Or WaitForSingleObject, or WaitForMultipleObjects, or MsgWaitForMultipleObjects? Should I use the (deprecated) Multimedia Timers? Where does WaitFor() come in?

More often than not, answers to these questions describe how these functions *shouldn’t* be used, but a lot of the time they skip or gloss over an actual proposed alternative. The correct answer, of course, is that ‘it depends’: on the type of application you’re writing, the situation you’re in, and what you’re waiting *for*. With that in mind, however, let’s look at some concrete answers for common situations!

Games

For games, the answer is actually pretty simple. Your main thread almost never wants to sleep or wait for anything! There are two common scenarios: If you have a fullscreen, 3D or action game: never wait, just continually run the game loop and you get improved FPS. If you have a puzzle, card or strategy-type game, you may want to lock the framerate to the screen’s refresh rate. In that case, the best and only place for your application to wait is inside Direct3D’s Present() method, after calling Device.Reset() with PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT. There it will happily render the scene while it waits for the appropriate time to elapse, and not waste any CPU cycles.

If you have a windowed game and it gets minimized, you again have two choices: either just keep the game running, or pause the game and wait for it to be restored. To keep running, just ignore the minimize event! If you want to wait efficiently until the player restores the window, the best way is something like this:

[code language=”delphi” gutter=”false”]
while (GameWindow.Minimized) do begin
WaitMessage; // Wait until new message arrives
PumpWindowMessages; // Process all pending WM_ messages
end;
[/code]

Assuming your WindowProc handles WM_ACTIVATE correctly to restore the game window’s state, this is all you need! Your application will receive exactly zero CPU time until a message arrives for it; it will immediately handle any messages that do come in (thus remaining responsive), and the instant the application is restored, normal play will resume.

Waiting for a worker Thread to finish

No contest here. This is exactly what the WaitFor() function was designed for. Use it! Note that “WaitFor” isn’t a Win32 API, but a version of this function is implemented by a wide variety of languages with threading support. FPC’s Windows implementation of TThread.WaitFor essentially does the following; if your chosen language doesn’t implement WaitFor, design something like this:

[code language=”delphi” gutter=”false”]
repeat
Outcome := MsgWaitForMultipleObjects([Threadhandle,SynchronizeEvent],INFINITE,QS_SENDMESSAGE);

case Outcome of
WAIT_OBJECT_0 {ThreadHandle} : ExitFlag := true;
WAIT_OBJECT_0+1{SynchronizeEvent}: CheckSynchronize; // Execute Synchronize() calls
WAIT_OBJECT_0+2{a WindowMessage} : PeekMessage(PM_NOREMOVE);
end;
until (ExitFlag);
[/code]

In other words, it calls MsgWaitForMultipleObjects specifying a handle to the thread to wait for, a global handle that is signalled if a thread calls Synchronize() on a method, and specifies to exit if a message is received from another thread or process. If the thread ending was the outcome, the function exits. Otherwise, it either executes the synchronized method, or peeks at the window messages, and starts waiting again. (If there’s a GUI, the application may wish to alter this behavior by waiting on QS_ALLINPUT and actually dispatching window messages instead of just peeking). Beware that if you’re waiting for a worker thread *from* the main thread, and the main thread also controls the GUI, make sure your language implementation includes a way to pump window messages during WaitFor(), or your GUI will stop responding up until the thread eventually completes.

The importance of the “SynchroniseEvent” wait allows other threads (including, potentially, the thread you’re waiting for) to execute Synchronized() procedure calls on the main thread while you wait. If this wasn’t included, attempting a synchronized procedure call (also know as an Asynchronous Procedure Call or APC) could cause a deadlock.

GUI application waiting for user input

WaitMessage. Very simple!

Non-GUI thread in an application that needs to poll something

This is where it gets tricky. Applications should *try* to avoid polling whenever they possibly can, because by definition it wastes CPU cycles: waking up a thread just to check one value and then going back to sleep is wasting two context switches worth of processor every time. So, if you’re in control of the information you’re polling for, rewrite it as an alert or an event mechanism (using a callback function, a custom window message, or a waithandle; whatever works for you!) so that you can just wait until it’s done. However, if you’re not in control of the source, sometimes you have to poll.

[code language=”delphi” gutter=”false”]
while not (<check some event>)
Sleep(50);
[/code]

Works best in this situation. 50ms is short enough to remain responsive when the event happens, but generous enough that the OS will be able to give several timeslices to other processes before it comes back to you. Note that internally, Windows implements Sleep() using a timeout waithandle and WaitForSingleObject(), so doing that does the same thing with more calls.

GUI thread in an application that needs to poll something

Similar to above, except that you need to be more responsive. You don’t want to wait 50 milliseconds to respond to window messages; that’s long enough to potentially cause irritation. So what we want is something like WaitMessage, but with a timeout. Here’s how:

[code language=”delphi” gutter=”false”]
while not (<check some event>) do begin
MsgWaitForMultipleObjects(0,nil,false,50,QS_ALLINPUT);
PumpWindowMessages;
end;
[/code]

Here, we call MsgWaitForMultipleObjects, using a timeout of 50 millisec and telling it we’re interested in all window messages, but don’t pass it any objects. This means that the function will wait until either the 50 milliseconds have elapsed, OR any window message is received (which we then want to pump immediately, being a GUI thread). Then as long as we’re awake, we check the polling condition before going back to sleep.

That’s it! A bunch of common situations, and the appropriate and graceful way to wait, sleep or yield your application. Hopefully this helps someone! Oh wait, I forgot something:

Sleep(0) and Sleep(1)

So, it turned out that in all of our situations, we never needed these. But they’re talked about quite a lot, so they must do something. What do they do?

Well, Sleep(0) yields the remainder of the current timeslice, but the thread remains ready to execute. This means that if the OS has no other threads or processes waiting to do something, it will return immediately. If there are other threads waiting, our thread will sleep and it’ll come back as soon as the scheduler finds time for it. The net effect? If it’s the only thing running on that processor, CPU Usage % on task manager will remain high. If other stuff is running, it will compete with that to run whenever possible.

Outcome? Not much is accomplished. If your application is actually busy doing something, you don’t want to randomly give up your timeslice. The scheduler will pre-empt you when it needs to: trust it! As long as it’s given you the processor, you should be using it. “ending early” like this is just generating needless context switches, with the result that your computer is slightly less efficient than it was before. If your application is *not* busy doing something, then you’re waiting! And you should use either the “wait for input” or the “wait and poll” methods described above. Don’t just sleep for tiny amounts of time.

Sleep(1) is slightly different. The 1 millisecond tells the scheduler “do not come back to me for at least 1 millisecond. (and it might be more like 5 or 10). Net result? This will reduce the CPU Usage % on task manager, even if it’s the only thing running, because you’re forcing the OS to ignore you temporarily. So it’s slightly ‘better’ in that sense. However, the question remains: why are you doing this? If your application is actually busy, you shouldn’t be sleeping. And if your application is actually waiting, you should use one of the waiting paradigms described above.

If your application is “just a little bit busy but you know, nothing important”, what you should be doing is using a worker thread, and setting it to a lower priority. That lets the OS scheduler control exactly when to allocate processor time. After all, even if you’re not doing anything important, it’s better than doing nothing at all. If the scheduler is able to give you that time, you may as well use it.

The final scenario where this might be tried is “my application needs to do something every 1 millisecond; otherwise it’s idle”. Sorry, but your approach is doomed: Sleep(1) guarantees at least a 1ms wait – it could be (and will probably be!) much more. If you really need this precise behavior, you need something better. That’s out of scope for this article though, it’s long enough already!

No Comment.

Add Your Comment