TTimer.OnTimer事件处理程序是否可重入?

Win*_*Oak 18 delphi c++builder

我的应用程序中有一个TTimer,每2秒触发一次,并调用我的事件处理程序HandleTimerEvent().HandleTimerEvent()函数修改共享资源,在返回之前可能需要10秒的时间才能执行.此外,我在事件处理程序中调用Sleep()有时放弃处理器.

我不确定C++构建器的TTimer对象在调用事件时是如何工作的,所以我刚才解释的场景让我思考,尤其是在先前的调用返回之前是否调用了HandleTimerEvent().

问题归结为几件事.

TTimer对象是否对事件进行排队?

在先前的调用返回之前,TTimer对象是否可以调用我的事件处理程序?

dth*_*rpe 32

此回复假定仍然实现了TTimer以使用WM_Timer消息.如果实施发生变化(自2005年起),请忽略.

不,TTimer对象不会对事件进行排队.它由Windows WM_Timer消息驱动,Windows不会让WM_TIMER消息在消息队列中堆叠.如果出现下一个计时器间隔,并且Windows发现WM_Timer消息已经在应用程序的消息队列中,则它不会向队列添加另一个WM_Timer消息.(对于WM_Paint,顺便说一下)

是的,即使先前的事件处理程序仍在执行,也可能触发TTimer.OnTimer事件.如果您在事件处理程序中执行任何允许应用程序处理消息的操作,则可以重新输入计时器事件.显而易见的是,如果您的事件处理程序调用Application.ProcessMessages,但它可能比那更微妙 - 如果您在事件处理程序中调用的任何内部调用Application.ProcessMessages,或调用PeekMessage/GetMessage + DispatchMessage,或打开模式对话框或者调用绑定到进程外COM对象的COM接口,然后处理应用程序消息队列中的消息,这可能包括您的下一个WM_Timer消息.

一个简单的解决方案是在您输入计时器事件处理程序时禁用计时器对象,并在退出计时器事件处理程序时重新启用它.这将阻止在事件处理程序仍在工作时触发计时器消息,无论代码的消息处理特性如何.

  • +1用于禁用计时器.为了演示禁用计时器的有效性(或者如果不这样做,可以轻松演示可能出现的问题),在计时器处理程序中显示一个消息框.如果您在进入时未禁用计时器,则消息框将叠加. (10认同)
  • 您还可以使用布尔标志来防止计时器事件处理程序中的重入,但禁用计时器本身要简单得多. (2认同)