Table of Contents

Introduction

The goal of this article is to show the practical use of different kinds of timers. First, we will see how to use the "standard" Win32 timers, then switch to multimedia timers, mention waitable timers and queue timers. I will try to make some general comparison between these solutions. So called high-resolution timer based on functions QueryPerformanceFrequency and QueryPerformanceCounter will not be taken into account because it can be used only to measure time intervals, and not to fire events in regular time intervals.

According to MSDN, An application uses a timer to schedule an event for a window after a specified time has elapsed. It means that if we create a timer and specify a time interval of uElapse milliseconds, it will do "something" every uElapse milliseconds, until we destroy it. It is up to us to specify what "something" is.

Timers are a useful feature offered to programmers by the OS. However, they can be easily misused: using timers for different kinds of polling (e.g. check every 200 milliseconds if the user entered some value into the edit box), is almost never a good idea. Good candidates for using timers are applications which do not depend that much on users' actions, but rather on time flow.

It is important to understand that the accuracy of timers is limited. Windows is not a real-time operating system (except Windows CE) and it is not reasonable to expect timers to handle very small time intervals (10 ms, for instance).

Standard Win32 Timers

When the term timer is used, it is almost always referred to this kind of timer. I use the term Win32 timer in this article simply to make a distinction between them and other timers. In some texts, these timers are called user timers because they are not kernel objects, unlike waitable and queue timers.

How do Win32 timers work? First, we create a timer, specify its elapse time, and (optionally) attach it to a window. After the timer is created, it sends WM_TIMER messages to the window message queue, or if no window was specified, to the application queue. We can process this message to call the code that we want to be executed in regular time intervals. The timer will send WM_TIMER messages until it is destroyed.

If we need to check our Inbox for new mail every half an hour, Win32 timers are all we want. However, for more accurate time measurement (elapsed time less than 1 sec), these timers are hardly the solution. The main reason is that timer posts WM_TIMER messages to a message queue, and we can never be sure when this message will be processed. Now, you might think that setting lpTimerFunc is a solution to this problem, but that is not the case. If you specify lpTimerFunc, the default window procedure calls it only when it processes WM_TIMER. So, we will still wait for WM_TIMER to be processed.

Note that with a Win32 timer event processing is done from the UI thread. The nice aspect of this fact is that we don't need to worry about corrupting our data from a timer event handler; on the flip side, the time spent in a WM_TIMER handler will affect the responsiveness of the UI. If you don't believe me, try calling something like ::Sleep(10000); within CTimersDlg::OnTimer().

Multimedia Timers

In the original version of this article, written 8 years ago, I described the multimedia timers in detail. In the meantime, they have become deprecated in favor of queue timers. If you are interested about the reasons, check out this Larry Osterman's blog post. Anyway, even at the time I originally wrote the article, the only reason to prefer multimedia timers over the queue timers was the fact that the later were introduced with Windows 2000 which was a relatively new system.

The multimedia timer is a high-resolution timer that does not post any messages to message queues. Instead, it calls the specified callback function directly on a separate thread (or, alternatively, it can set or pulse the specific event, but that option will not be covered in this article). Therefore, it is more accurate than the standard Win32 timer, but also more dangerous. Here, we do not have a message queue to protect us if we specify short elapse time.

To use multimedia timers in your projects, you should include Mmsystem.h, and link it with Winmm.lib.

The first step when using multimedia timers is setting the timer resolution. What is timer resolution? It determines the accuracy of the timer. For instance, if elapse time is 1000, and resolution is 50, multimedia timer will "tick" every 950 - 1050 milliseconds.

That sounds great. Why don't we just set the timer resolution to zero, and have an absolutely accurate timer? That's because different systems support different minimum values for the multimedia timer resolution. We can obtain this minimum value by calling:

MMRESULT timeGetDevCaps(LPTIMECAPS ptc, UINT cbtc);

Arguments

ptc - Pointer to a TIMECAPS structure. It is filled with information about the resolution of the timer device

cbtc - Size of TIMECAPS (sizeof (TIMECAPS)).

Return Value

TIMERR_NOERROR if successful or TIMERR_STRUCT if it fails

TIMECAPS is pretty simple:

typedefstruct {
UINT wPeriodMin;
UINT wPeriodMax;
} TIMECAPS;

wPeriodMin - Minimum supported resolution

wPeriodMax - Maximum supported resolution

We need to pick our minimum resolution to be in this range. Now, when we have it, let's set the resolution. We will do it by calling the function:

MMRESULT timeBeginPeriod(UINT uPeriod);

Arguments

uPeriod - Minimum timer resolution

Return Value

TIMERR_NOERROR if successful or TIMERR_NOCANDO if the resolution specified in uPeriod is out of range

Now that we set the resolution, let's create the timer. The multimedia timer equivalent of SetTimer, looks like this:

The example shown above is written in a way to resemble the handling of standard Win32 timers. In practice, however, I wrap the functionality of multimedia timers in a separate class, and I recommend you to do the same.

As I mentioned before, a multimedia timer runs on its own thread.

Waitable Timers

Waitable timers were introduced with Windows 98 and Windows NT 4.0. and they were designed to work with threads that need to block for some times. These timers are kernel objects which are signaled in the specified time, or in regular time intervals. They can specify the callback function (actually, an asynchronous procedure call, or APC) which gets called when timer gets signaled. This callback function is usually called a completion routine.

In order to enable execution of the completion routine, the thread must be in alertable state (executing SleepEx(), WaitForSingleObjectEx() , WaitForMultipleObjectsEx(), MsgWaitForMultipleObjectsEx() , SignalObjectAndWait() functions). In practice, this means that our main thread will be blocked while we are using waitable timers.

To start working with a waitable timer, we must open an existing timer, or create the new one. Creating can be accomplished with a call to:

As you can see, we don't have OnButtonStop() now. As soon as we set the timer, we must put our calling thread into alertable state, and wait. This means that we cannot do anything in the main thread until we finish with the timer. Of course, nothing prevents us from launching a separate worker thread which won't be blocked.

What can we conclude about waitable timers? They do not spend much CPU time and they do not need a message queue. The main problem is that the thread which sets the waitable timer must put itself in an alertable state, or the completion routine will never be called.

Queue Timers

The last kind of Windows - supported timers that we are going to read about in this article is queue timers. They were introduced with Windows 2000.

Queue timers are lightweight kernel objects that reside in timer queues. Like most timers, they enable us to specify the callback function to be called when the specified due time arrives. In this case, the operation is performed by a thread in the Windows thread pool.

Here, for the sake of simplicity, we are not going to create our timer queues. Instead, we will put our queue timers into default timer queue, provided by the OS.

First, we need to create a timer and add it to the default timer queue. For this, we'll make a call to:

As you can see, queue timers are pretty easy to use. I can also add that they are very accurate, and "resource friendly".

As I noted at the beginning of this chapter, queue timers are supported on Windows 2000 and later. If you do not want to support older Windows versions, they are perfect, and should be used instead of multimedia timers.

Conclusion

What's the moral of the whole story?

When you decide that you need a timer in your application, choosing between the different timer variants should not be that hard. Follow these simple rules:

If you want your application to work on every 32 bit Windows platform, you do not need high precision, and the callback operation is fast enough not to disrupt the UI responsiveness, use a standard Win32 timer.

If you want your application to work on every 32 bit Windows platform, and you need high precision, use the multimedia timer.

If you want your application to work on Windows 98/NT4 and later, you need low system overhead, and can afford to block the calling thread, use the waitable timer.

If you want a high-precision, low-overhead, non-blocking timer that will work on Windows 2000 and later, use the queue timer.

Hi! Are you sure it's correct to call ::CloseHandle after calling ::DeleteTimerQueueTimer in OnButtonStop for Queue Timers?

Also, IMHO, could be better to suggest that it's safer to signal a kernel object using the third parameter of the call to ::DeleteTimerQueueTimer, before to make any cleanup of structures related to TimerProc, in order to prevent potential races.

First, it's probably just obvious that "resolution" is supposed to be "m_uResolution" in the last line. Typo, I assume?

Second, this line makes no sense to me:

m_uResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax);

What is the point of the min/max stuff? Windows has given you the Min and Max resolutions already. If m_uResolution is supposed to be the minimum, then m_uResolution=tc.wPeriodMin should be sufficient. If you call max(tc.wPeriodMin, 0), I guess it's to make sure windows didn't give you a negative resolution? The windows documentation on TIMECAPS and timeGetDevCaps is typically light, but I don't see any indication that getting junk back from timeGetDevCaps is a possibility. It's not actually wrong I guess, but it's confusing and unnessesary as far as I can tell.

- If I am using a periodic multimedia timer like the one described here, what would happen if my thread process takes longer than the thread time period? Say, my thread takes 10 ms to execute but I have the timer setup to execute the thread every 5 ms. What would happen in this case.

It has been my experience, through experimentation, that many Windows time functions have a low granularity - 10-15ms.
By setting the multimedia timer to 1ms intervals, this also affects others Window time functions, such as GetTickCount.

This function affects a global Windows setting. Windows uses the lowest value (that is, highest resolution) requested by any process. Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. High resolutions can also prevent the CPU power management system from entering power-saving modes. Setting a higher resolution does not improve the accuracy of the high-resolution performance counter.

I did not mention QPF, QPC because it was out of the scope of the article. Using QPC has 20+ times the overhead of GetTickCount, which has twice the overhead of rttsc.

It is possible to use QPF, QPC to very accurately measure time - not intervals - with a little extra coding. The latest code I have is accurate to the sub-microsecond but due to the overhead in high-performance servers, I don't use it very often.

Also, what are the ramnifications of just using a forever loop in a thread that uses a thread sleep call? So let's say that I periodically want to send some data every X milliseconds. If I make the thread sleep for X seconds and send the data out periodically this way, even if its not exactly at X ms intervals, I would be okay with that. Do you see any issues with this? What I am doing has timing requirements but it is not time critical and delays like this would be okay.

Not that I am aware of, but I haven't really followed the timer APIs for Windows 7, so I may be wrong.

ValleyDoll wrote:

So let's say that I periodically want to send some data every X milliseconds. If
I make the thread sleep for X seconds and send the data out periodically this
way, even if its not exactly at X ms intervals, I would be okay with that. Do
you see any issues with this?

I guess it would work, but why don't you use some existing timer that runs the handler in a separate thread? Queue timers look like a good mechanism for what you are asking.