If my WM_TIMER handler takes longer than the timer period, will my queue fill up with WM_TIMER messages?


A customer was worried that they may have a problem with their message queue filling with WM_TIMER messages. "If my WM_TIMER handler takes longer than the timer period, will my queue fill up with WM_TIMER messages?"

As we should know by now, timer messages are generated on demand:

The WM_TIMER message is a low-priority message. The Get­Message and Peek­Message functions post this message only when no other higher-priority messages are in the thread's message queue.

Here's the basic algorithm. (I'm ignoring filtering and I'm assuming that messages are removed.)

  • Look for a posted message. If one exists, then return it.
  • Was Post­Quit­Message called? If so, then generate and return a WM_QUIT message.
  • Look for an input message. If one exists, then return it.
  • Did the mouse move since the last call? If so, then generate and return a WM_MOUSE­MOVE message.
  • Does a window need to be repainted? If so, then generate and return a WM_PAINT message.
  • Is there a timer that has elapsed? If so, then generate and return a WM_TIMER message.

Notice that the generated messages are generated on demand by message retrieval functions. If you never call a message retrieval function, then no messages are generated. And in the case where the messages are removed (i.e., you use Get­Message or you use Peek­Message with PM_REMOVE), the messages are removed immediately after being generated, so they don't hang around very long at all.

In particular, if your WM_TIMER handler takes longer than the timer period, and it doesn't call a message retrieval function, then there is no opportunity for another WM_TIMER message to be generated. Only when you call a message retrieval function does there become a possibility for a WM_TIMER message to be generated.

Comments (15)
  1. AC says:

    What happens to the non-generated messages when the program gets stuck and doesn't process them?

    Windows will ghost the window and display "not responding", but do the messages keep queueing up, consuming more and more memory, or do they get discarded at some point?

  2. Ben Voigt says:

    @AC: Posted real messages will queue up to the thread's message queue limit.  Once the queue is full, new messages will be rejected (this is almost the same as discard most recent, except that the message source is told about the problem).

  3. Koro says:

    @AC: They queue up, but there is an upper limit on thread message queue size.

  4. Medinoc says:

    This means "elapsed timer" is a flag and not a counter. Good to know.

  5. SimonRev says:

    The last I checked the queue limit was about 10000 — which really means that is what it was the last time I messed up and put an infinite loop in the UI thread and could see that I had 10000 items that I had posted to the message queue pending before things fell apart.

  6. Jeffrey Bosboom says:

    In what situations would a timer with shorter period than its handler's execution time be useful?  To me it just sounds like a bug, but maybe Win32 timers are used for things not really related to time (not even soft real-time)?

  7. Nikolai says:

    Hello Raymond,

    sorry to post it as a comment, didn't find an easy method to be "a customer that worried about" :-) but anyway:

    Is there a way to initialize WinHttp working pool threads? I'm using async WinHttp with call-back function set by WinHttpSetStatusCallback(). In this call-back I want to use COM, I need to setup _set_se_translator, etc.

    Do I need to call CoInitialize()/CoUninitialize() pair every time in the call-back function? Or there is a way to do it once? I didn't get answer on that question and if it's interesting for you, may be you can make a post or so with your usual decent explanations…

    Thanks in advance,

    Nikolai

  8. Nikolai says:

    Jeffrey, I can imagine situation when most of the timer calls handled promptly and only one or two has a delay due to disk or network access or so..

  9. Ian says:

    I wonder whether the original query was really asking (if perhaps clumsily) what might happen if a timer is being serviced slower than its repeat rate, and the bit about filling up the message queue with WM_TIMER messages was just a red-herring because the questioner assumed this would be the most immediate consequence.

    Does the timer itself keep an internal count of how many times the timeout has elapsed but no WM_TIMER message has yet been generated? Is there an upper limit to this and if so what is it? What would happen if this limit were to be exceeded? (Is there a 32-bit integer that wraps round to zero perhaps?)

  10. Neil says:

    @Ian: WM_TIMER just means that (at least) the specified time has elapsed since the timer was set (or previous WM_TIMER was sent for a repeating timer). It doesn't guarantee anything else. (I don't think it could, even if it wanted to.)

  11. blackTofu says:

    Has it changed "recently"? I still remember Jefrey's book "Advanced Windows" where he claimed that we check first for "send" messages, then for posted, then for send messages again.

  12. Gabe says:

    Jeffrey Bosboom: I'm sure a typical situation is a movie or video game with a set framerate, say 50fps. You need to know when to render the next frame so you set a 20ms timer.

    If it turns out that a particular system takes 40ms to render a frame, that's certainly not a bug — you just end up dropping frames. You obviously wouldn't want all those extra timer messages accumulating somewhere.

  13. Mirinth says:

    @Jeffrey, here's a specific example of Nikolai's suggestion:

    Imagine you're building a network of computers to take the hit from DDoS attacks so the main servers can survive an attack. The basic idea for the shield is to check for and handle requests first (since throughput is critical) and heartbeat timers second. The main servers watch for the heartbeat and warn the administrators if it's too late, assuming that an attack is in progress (or a shield is otherwise dead) since the shield should have sent the beat otherwise.

    In the meantime, the shield is doing its best to sort through all the incoming data, filter out the bad stuff and forward the good to the main servers. When the shield is under attack, it always finds something other than the timer messages, so it handles those and ignores the timer to keep throughput high. High throughput is the shield's job, after all.

    But DDoS attacks have a nasty tendency to last longer than you expect, and those timer messages are piling up in the meantime. If you ignore them long enough, could a DDoS actually crash the shield and shut you down anyway? Is this the kind of thing you need to worry about? Should you go to all the effort to design, build and test the extra complexity involved in checking for and throwing out the heartbeats in a flood?

  14. Mirinth says:

    Just wanted to say, I like your example, Gabe. I never would have thought you could be late every time and that's okay.

  15. Someone says:

    This whole "In what situations would a timer with shorter period than its handler's execution time be useful? To me it just sounds like a bug" statement is just wrong.

    Imagine, you have a program that needs to poll some external resource regularly (for example: an very simple e-mail client polling a database status field every minute). Most of the time, the request (SQL query) will be executed within fractions of a second, but there is no *bug* in your program if the request will take a little longer than 1 minute, due to server-side activities like data reorganization, virus scanning, activities of other VMs at the same host etc etc etc.

    The program should just process the results from the requests (fast or slow), and then proceed at the next interval.

    In general, the Windows timers gives your GUI thread the opportunity to execute work (at regular intervals) when and only when this GUI thread is idle. If you need otherwise (for example, operation in a background, without any GUI), use Waitable Timers (msdn.microsoft.com/…/ms687012%28v=vs.85%29.aspx).

Comments are closed.

Skip to main content