delphi计时器比计时器服务中断程序更快

Iam*_*man 4 delphi timer interrupt access-violation

嗨我被要求为某人维护一个基于Delphi 5的程序,并且该程序使用一个计时器对象每50毫秒进行一次滴答,并且每次计时它运行单线程代码块.我只是想知道,如果执行这段代码所花费的时间长于计时器滴答间隔会发生什么,这会不会很糟糕?例如,它是否会导致访问冲突等问题?Delphi默认如何处理这种情况?非常感谢.

Rob*_*edy 6

计时器的刻度不会中断您的代码.

定时器滴答以窗口消息的形式提供.窗口消息只能在您检查消息队列中是否有新消息时到达.当您的计时器事件处理程序返回并且程序恢复其事件循环时会自动发生,但您可以通过调用显式触发它Application.ProcessMessages.不过,请不要这样说; 从长远来看,它很少解决问题.

如果你没有检查你的timer-tick处理程序中的消息队列,那么你的处理程序将永远不会开始运行,而它仍处理上一个tick.

即使你确实检查了队列,所有发生的事情都是递归调用 tick处理程序.毕竟,它都在一个线程中运行.然而,递归计时器处理可能不是你想要发生的,所以我将再次建议不要在消息处理程序检查消息.

此外,如果您的计时器处理程序需要很长时间才能运行,计时器消息永远不会"堆积".定时器消息是"假的",因为它们实际上不会定期添加到消息队列中.相反,操作系统将在程序检查队列以获取更多消息时合成计时器消息.如果队列中没有优先级较高的消息,并且计时器间隔已过,则OS将返回一条wm_Timer消息.如果检查更多消息,则队列中将没有计时器消息.特别是,队列中不会有多个计时器消息.

进一步阅读:

  • 注意,"WM_TIMER"消息是合成的低优先级消息.在定时器间隔结束且队列中没有其他消息之前,不会生成它. (5认同)
  • 这仍然没有回答部分问题:如果他没有在他的事件处理程序中调用Application.ProcessMessages(事实上他不应该),下次调用何时会发生?它会在事件处理程序完成后立即发生,因为已经有WM_TIMER消息等待处理吗?或者它会被丢弃,只有在下次定时器触发时才调用该事件? (2认同)
  • @dummzeuch - 它不会被丢弃.在事件处理程序完成后立即再次调用事件处理程序*(在处理队列中的所有其他消息之后)* (2认同)

J..*_*... 6

这个问题的关键部分是:

...如果执行此代码块所花费的时间长于计时器滴答间隔,会发生什么情况呢?

这不是很好,但它不是一个显示塞子,它肯定不会导致访问违规.Delphi TTimer是使用WinAPI SetTimer函数实现的.

您可能天真地认为,如果您的计时器的处理程序花费的时间超过了处理的时间间隔,那么计时器将继续在消息队列中堆积消息,并且您的程序将有效地锁定大量的计时器消息,而这些消息一直没有希望处理.值得庆幸的是,这并不是计时器的工作方式.文档可以解释一些问题.

WM_TIMER消息

WM_TIMER消息是低优先级消息.仅当线程的消息队列中没有其他更高优先级的消息时,GetMessage和PeekMessage函数才会发布此消息.

现在,在Windows应用程序中并没有真正的"高"和"低"优先级消息的概念,虽然这个语句有点含糊不清,但我们可以将上下文表示这WM_TIMER是一个未发布到应用程序的消息消息队列,而是在设置定时器时响应于GetMessagePeekMessage调用而生成SetTimer,当该定时器的间隔已经过去时,以及队列中已经没有其他消息时.

因此,虽然处理程序处理期间可能会经过计时器间隔,但在发生这种情况时进入的任何其他消息仍将正常进入队列,并在处理程序完成后处理.只有在队列再次清空后,才会WM_TIMER生成另一条消息.

计时器事件,因此,将执行或者在周期的时间间隔的速度快你的应用程序可以处理它们,无论最终是最长的.但是,如果您确实有过快的定时器消息,并且您的计时器处理程序的处理时间很长,那么您的应用程序的响应能力会受到影响.它不会没有响应,但所有其他消息处理将被限制为在计时器的事件处理程序执行时间间隔内进行处理.这可能会使您的应用程序感到迟钝.


要演示,请创建一个新的表单应用程序并添加一个TTimer间隔设置为的组件10.然后附加此处理程序:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  sleep(200);
end;
Run Code Online (Sandbox Code Playgroud)

程序运行时,尝试移动窗口.我们所做的是基本上将应用程序的消息处理量化为200ms间隔(定时器的事件处理程序执行的持续时间).