TTimer实际上如何在内部工作?

时间:2018-09-26 11:28:59

标签: windows delphi winapi rad-studio ttimer

间隔设置为1秒的TTimer每1秒发送一条消息。在应用程序的消息循环中处理此消息,这导致触发OnTimer事件。
如果应用程序很忙,没有时间处理消息循环,则将跳过OnTimer事件。

我知道TTimer内部使用SetTimer

我的问题是:

  1. TTimer是否使用内部/独立线程(通过SetTimer)?
  2. 如果有模式的MessageDlg正在“阻止”表单,那么保存计时器的表单(甚至包括其OnTimer)怎么仍能起作用? (请参见下面的代码)
  3. 文档说SetTimer至少需要Win2000。 TTimer是如何在Win98中实现的?

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
 Caption = i;
 i++;
 MessageDlg(stuff);      <----- we "block" application here but form's caption is still updated.
}

2 个答案:

答案 0 :(得分:5)

  

如果应用程序繁忙且没有时间处理消息循环,则将跳过OnTimer事件。

这是正确的。 MSDN上的Thisthis博客文章提供了一些内部实现细节,特别是它们提到到期计时器导致设置了消息队列状态的QS_TIMER标志。没有更多的时间流逝将导致队列状态标志被进一步设置。设置此标志且[Peek|Get]Message无法选择任何更高优先级的消息时,将生成计时器消息。

尽管计时器消息没有堆积在队列中,但是在执行先前的事件处理程序时,有可能再次触发计时器。当处理程序中的代码执行时间超过计时器间隔并允许重新输入时,这是可能的。如果计时器处理程序导致应用程序处理排队的消息,则可能会清除任何待处理的队列状态标志并再次发布消息,这可能会导致计时器在处理程序完成执行之前触发。

  

TTimer是否使用内部/独立线程(通过SetTimer)?

不。在主线程中创建了一个实用程序窗口,它将接收计时器消息。收到计时器消息后,如果分配了此窗口,则此窗口将调用事件处理程序。

  

保存计时器的表单(甚至包括它的OnTimer)为何如此   模态MessageDlg正在“阻止”表单,仍然可以做些什么?

模态循环继续处理队列,它在调用HandleMessage的循环中调用应用程序的ProcessMessage。因此,计时器消息仍在处理。

这是上述再次进入的潜在原因。您可以使用标志或禁用/启用计时器来防止这种情况。或者将处理程序中的所有消息处理都排除在外。

  

文档说SetTimer至少需要Win2000。 TTimer是如何在Win98中实现的

相同。文档不断变化,有时MSDN会从最低要求中删除不受支持的OS版本-不一致。我的XE2 API文档指出:

  

最低操作系统 Windows 95,Windows NT 3.1

用于WM_TIMER消息。

答案 1 :(得分:4)

WM_TIMER消息永远不会放在消息队列中。它们在队列为空并且设置了指示计时器已过期的标志时生成。因此,队列中一次不会出现多个WM_TIMER消息,并且如果您的应用程序太忙而无法处理队列,则不会有很多WM_TIMER消息等待处理。

WM_PAINT消息的工作方式相同。