Timer Messages Are Not Asynchronous

Non-Windows programs written for the IBM PC and compatibles can use the timer tick interrupt by intercepting Interrupt 08H or Interrupt 1CH (a software interrupt called by the BIOS Interrupt 08H handler). When the hardware interrupt occurs, the program currently running is suspended, and control passes to the interrupt handler. When the interrupt handler is done, it passes control back to the interrupted program.

Like the hardware keyboard and mouse interrupts, the hardware timer tick interrupt is sometimes called an asynchronous interrupt because it occurs randomly with respect to the program that it interrupts. (Actually, the term isochronous is more accurate than asynchronous for a timer interrupt because the interrupts occur at equal intervals. But the interrupts are still asynchronous with respect to other processing.)

Although the SYSTEM.DRV driver also handles asynchronous Interrupt 08H clock ticks, the WM_TIMER messages that Windows sends to applications are not asynchronous. The WM_TIMER messages are placed in the normal message queue and ordered with all the other messages. Therefore, if you specify 1000 msec in the SetTimer call, your program is not guaranteed to receive a WM_TIMER message every second or even (as I mentioned above) every 989 msec. If another application is busy for more than a second, your program will not get any WM_TIMER messages during that time. Only when the other application yields control to Windows (by calling GetMessage, PeekMessage, or WaitMessage) will your program retrieve its next WM_TIMER message from the queue.

You can easily demonstrate this to yourself with the CLOCK program included with Windows or with the sample programs shown in this chapter. If another program has a long paint job and does not immediately relinquish control, CLOCK will stop. When CLOCK regains control, it will jump ahead to the correct time. In fact, Windows handles WM_TIMER messages much like WM_PAINT messages. Both these messages are low priority. If a program's message queue contains only WM_PAINT or WM_TIMER messages, and another program's message queue contains messages other than WM_PAINT or WM_TIMER, Windows will pass control to the other application.

The WM_TIMER messages are similar to WM_PAINT messages in another respect: Windows does not keep loading up the message queue with multiple WM_TIMER messages. Instead, Windows combines several WM_TIMER messages in the message queue into a single message. Therefore, the application won't get a bunch of them all at once, although it may get two WM_TIMER messages in quick succession. An application cannot determine the number of ”missing“ WM_TIMER messages that result from this process.

When CLOCK regains control and jumps ahead to the correct time, it is not because it gets several WM_TIMER messages in a row. CLOCK must determine the actual time and then set itself. The WM_TIMER messages only inform CLOCK when it should be updated. A program can't keep time itself solely by counting WM_TIMER messages. (Later in this chapter we will write a clock application that updates every second, and we'll see precisely how this is accomplished.)

For convenience, I'll be talking about the timer in terms such as ”getting a WM_TIMER message every second.“ But keep in mind that these messages are not precise clock tick interrupts.