Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

delphi timer ticks faster than timer service interrupt routine

Hi I have been asked to maintain a Delphi 5 based program for someone, and the program is using a timer object to tick every 50 milli-seconds and upon each time-up it runs the block of single threaded code. I am just wondering, what would happen if the time taken to execute this block of code is longer than the timer tick interval, would this be bad? For example could it cause problems like access violation? How does Delphi handle this kind of situation by default? Thanks a lot.

like image 644
Iamthedudeman Avatar asked Dec 14 '22 21:12

Iamthedudeman


2 Answers

The critical part of this question is :

... what would happen if the time taken to execute this block of code is longer than the timer tick interval, would this be bad?

It's not great, but it's not a show stopper and it certainly cannot cause access violations. Delphi's TTimer is implemented using the WinAPI SetTimer function.

You might naively think that if your timer's handler took longer than the interval to process that the timer would continue to pile up messages in the message queue and your program would effectively lock up with a flood of timer messages that had no hope of ever all being processed. Thankfully, this isn't exactly how timers work. The documentation can shed some light.

WM_TIMER message

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

Now, there isn't really a concept of "high" and "low" priority messages in a windows application, and while this statement is a little ambiguous we can take the context to mean that WM_TIMER is a message that is not posted to the application's message queue but rather generated in response to a GetMessage or PeekMessage call when a timer has been set with SetTimer, when that timer's interval has elapsed, and when there are no other messages already in the queue.

So, while the timer interval may elapse during your handler's processing, any other messages that come in while this is happening will still enter the queue normally and will be processed once your handler completes. Only once the queue has been emptied again will another WM_TIMER message be generated.

The timer events, therefore, will execute either at the rate of the tick interval or as fast as your application can process them, whichever ends up being longest. If you do have timer messages coming in too quickly, however, and your timer handler's processing time is long then your application's responsiveness can suffer. It won't become unresponsive, but all other message processing will be restricted to being processed at the interval of your timer's event handler execution time. This can make your application feel sluggish.


Example

To demonstrate, create a new forms application and add a TTimer component with an interval set to 10. Then attach this handler :

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  sleep(200);
end;

While the program is running, try moving the window around. What we have done is to essentially quantize the application's message processing to a 200ms interval (the duration of the timer's event handler execution).

like image 182
J... Avatar answered May 10 '23 21:05

J...


Ticks of the timer do not interrupt your code.

Timer ticks are delivered in the form of window messages. Window messages can only arrive when you check the message queue for new messages. That happens automatically when your timer event handler returns and your program resumes its event loop, but you can trigger it explicitly by calling Application.ProcessMessages. Don't call that, though; it seldom solves problems in the long run.

If you don't check the message queue in your timer-tick handler, then your handler will never start running a second time while it's still handling a previous tick.

Even if you do check the queue, all that happens is that the tick handler will be called recursively. After all, it's all running in a single thread. Recursive timer handling probably isn't what you want to happen, though, so I'll again counsel against checking for messages in a message handler.

Furthermore, timer messages can never "pile up" if your timer handler takes a long time to run. Timer messages are "fake" in that they don't actually get added to the message queue at regular intervals. Instead, the OS will synthesize a timer message at the time your program checks the queue for more messages. If there are no higher-priority messages in the queue, and the timer interval has elapsed, then the OS will return a wm_Timer message. If you don't check for more messages, then there will be no timer message in the queue. In particular, there will not be multiple timer messages in the queue.

Further reading:

  • Stack Overflow: How does the message queue work in Win32?
  • Dr. Dobbs: Inside the Windows Messaging System
like image 23
Rob Kennedy Avatar answered May 10 '23 19:05

Rob Kennedy