您好我被要求为某人维护一个基于Delphi 5的程序,并且该程序使用一个计时器对象每50毫秒打勾一次,并且每次计时它运行单线程代码块。我只是想知道,如果执行这段代码所花费的时间长于计时器滴答间隔会发生什么,这会不会很糟糕?例如,它是否会导致访问冲突等问题? Delphi默认如何处理这种情况?非常感谢。
答案 0 :(得分:6)
定时器的定时器不会中断您的代码。
计时器刻度以窗口消息的形式提供。窗口消息只能在您检查消息队列中是否有新消息时到达。当您的计时器事件处理程序返回并且程序恢复其事件循环时,这会自动发生,但您可以通过调用Application.ProcessMessages
显式触发它。不过不要这样说;从长远来看,它很少解决问题。
如果你没有检查你的计时器滴答处理程序中的消息队列,那么你的处理程序将永远不会再次开始运行,而它仍处理上一个滴答。
即使你做检查队列,所有发生的事情都是滴答处理程序将被称为递归。毕竟,它都在一个线程中运行。递归计时器处理可能不是你想要发生什么,所以我再次建议反对检查消息处理程序中的消息。
此外,计时器消息永远不会堆积在一起。如果您的计时器处理程序需要很长时间才能运行定时器消息是"假的"因为它们实际上并没有定期添加到消息队列中。相反,操作系统将在程序检查队列以获取更多消息时合成计时器消息。如果队列中没有优先级较高的消息,并且计时器间隔已过,则操作系统将返回wm_Timer
消息。如果您不检查更多消息,则队列中将没有计时器消息。特别是,队列中不会有多个计时器消息。
进一步阅读:
答案 1 :(得分:6)
这个问题的关键部分是:
...如果执行此代码块所花费的时间长于计时器滴答间隔,会发生什么情况呢?
它并不好,但它不是一个显示阻止者,它肯定不会导致访问违规。 Delphi的TTimer
是使用WinAPI SetTimer
函数实现的。
你可能会天真地认为,如果你的计时器的处理程序花费的时间超过了处理时间间隔,那么计时器将继续堆积消息队列中的消息,并且你的程序会有效锁定大量的计时器消息没有希望永远都被处理。值得庆幸的是,这并不是计时器的工作方式。文档可以解释一下。
<强> WM_TIMER message 强>
WM_TIMER消息是低优先级消息。仅当线程的消息队列中没有其他更高优先级的消息时,GetMessage和PeekMessage函数才会发布此消息。
现在,并没有真正的&#34;高&#34;和&#34;低&#34; Windows应用程序中的优先级消息,虽然这个语句有点含糊不清,但我们可以将上下文表示WM_TIMER
是一条未发布到应用程序消息队列但是生成响应的消息当定时器已设置为GetMessage
时,当该定时器的间隔已经过去时,以及队列中已有其他消息时,PeekMessage
或SetTimer
呼叫。
因此,虽然在处理程序的处理期间可能会超时,但在发生这种情况时进入的任何其他消息仍然会正常进入队列并在处理程序后处理完成。只有在队列再次清空后,才会生成另一条WM_TIMER
消息。
因此,计时器事件将以剔除间隔或的速率执行 ,速度与应用程序可以处理它们一样快,以最长时间为准。但是,如果您确实有过快的定时器消息,并且您的计时器处理程序的处理时间很长,那么您的应用程序的响应能力会受到影响。它不会成为无响应,但所有其他消息处理将被限制为在计时器的事件处理程序执行时间间隔内进行处理。这可能会使您的应用程序感到迟钝。
示例强>
要演示,请创建新的表单应用程序并添加TTimer
组件,并将间隔设置为10
。然后附上这个处理程序:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
sleep(200);
end;
程序运行时,请尝试移动窗口。我们所做的是基本上将应用程序的消息处理量化为200ms间隔(定时器的事件处理程序执行的持续时间)。