【问题标题】:How TTimer actually works internally?TTimer 实际上是如何在内部工作的?
【发布时间】:2018-09-26 11:28:58
【问题描述】:

间隔设置为 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.
}

【问题讨论】:

  • 这是一个低优先级的windows消息WM_TIMER。见using timers. 不一定对精确时间测量有用。
  • 为什么这个问题被否决了?它无效/不相关?
  • 完全是推测,但否决票可能与所要求的内容和接受的内容有关。它们似乎完全不相关,这可能表明您问错了问题。
  • @SertacAkyuz - 1. 在我发布问题后立即投下了反对票。所以它与接受的答案无关。 2. 事实上,基思提供的答案并没有回答我的具体问题。然而,它确实为这个问题带来了一些启示。而且因为它是唯一(好的)答案.... :)
  • “文档说SetTimer最低要求Win2000。TTimer在Win98中是如何实现的?”SetTimer 已经存在于 Windows 98/95 甚至 Windows 3 上。微软在其文档中简单地放弃了对早于 Windows 2000 的 Windows 版本的任何引用。

标签: windows delphi winapi rad-studio ttimer


【解决方案1】:

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

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

虽然定时器消息不会堆积在队列中,但在前一个事件处理程序正在执行时,可能会再次触发定时器。当处理程序中的代码执行时间超过计时器间隔并且允许重新进入时,这是可能的。如果计时器处理程序导致应用程序处理排队的消息,则可能会清除任何未决队列状态标志并再次发布消息,这可能会导致计时器在处理程序完成执行之前触发。

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

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

保存计时器的表单(甚至它的 OnTimer)是怎么来的? 如果模态 MessageDlg 正在“阻止”表单,仍然可以做一些事情吗?

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

这是上述重入的潜在原因。您可以使用标志或禁用/启用计时器来防止这种情况。或者完全排除处理程序中的任何消息处理。

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

一样。文档不断变化,有时 MSDN 会从最低要求中删除不受支持的操作系统版本 - 相当不一致。我的 XE2 API 文档状态:

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

对于WM_TIMER 消息。

【讨论】:

    【解决方案2】:

    WM_TIMER 消息永远不会放在消息队列中。它们是在队列为空并且设置了指示计时器已过期的标志时生成的。因此,队列中一次不能有超过一条 WM_TIMER 消息,如果您的应用程序太忙而无法处理队列,您就不会收到大量等待处理的 WM_TIMER 消息。

    WM_PAINT 消息的工作方式相同。

    【讨论】:

    • WM_TIMER 文档确认 WM_TIMER 是一个低优先级消息,但它没有说明是否只发布了一条消息。
    • @Rigel 我阅读了 Keith 链接的附加答案并重新阅读了文档和“消息由 GetMessage 或 PeekMessage 函数发布”部分。似乎表明基思是对的。
    • 好的。然后接受基思的回答。 +1,谢谢你们。我正在阅读您现在提供的 3 个文档来源。
    • 所问的 3 点似乎都没有得到解决。此外,似乎不同意从未提出过的主张。我的意思是这个问题没有声称或提到消息已排队,它只是告诉消息是由消息循环处理的,这是正确的。然而被接受,我想我完全失去了它。
    • @SertacAkyuz - 我肯定会接受一个更好的答案是发布一个:)
    猜你喜欢
    • 2014-10-06
    • 2012-01-24
    • 2014-09-24
    • 1970-01-01
    • 1970-01-01
    • 2021-01-21
    • 2011-09-27
    • 2021-12-16
    • 2013-03-14
    相关资源
    最近更新 更多