我的单线程delphi 2009应用程序(尚未完全完成)开始出现Application.ProcessMessages挂起的问题。我的应用程序有一个TTimer对象,该对象每100毫秒触发一次以轮询外部设备。当发生某些更改时,我使用Application.ProcessMessages更新屏幕,因此该应用程序仍然可以响应。

其中之一是在网格OnMouseDown事件中。在那里,它实际上挂了一个Application.ProcessMessages。删除那没问题,除了我很快发现了另一个也在阻塞的Application.ProcessMessages。

我认为可能正在发生的事情是,TTimer(在我当前正在调试的应用程序模式下)可能需要太长时间才能完成。我阻止了TTimer.OnTimer事件处理程序重新输入相同的代码(请参见下文):

procedure TfrmMeas.tmrCheckTimer(Sender: TObject);
begin
  if m_CheckTimerBusy then
    exit;

  m_CheckTimerBusy:=true;
  try
    PollForAndShowMeasurements;
  finally
    m_CheckTimerBusy:=false;
  end;
end;


调用Application.ProcessMessages在什么地方是不好的做法? OnPaint例程会引起人们的注意,认为这是没有意义的。

有什么一般性建议吗?

我很惊讶地看到开发中的这一点出现了这种问题!

最佳答案

我对TApplication.ProcessMessages的建议是永远不要使用它-放置它根本不是一个好方法。

想象一下调用它是做什么的:您的应用程序运行一个消息循环-在其中按顺序处理Windows消息(由OS,其他应用程序,您的应用程序等生成)-然后在其中一个消息处理过程中, -再次运行整个消息循环,而不必控制要处理的消息,将要处理的消息量,是否有任何消息进入其自己的消息循环...以及是否存在任何可重入性问题。这就是我所说的惹麻烦。

有时有充分的理由来处理某些Windows消息(特别是不挂起其他线程),或处理定向到特定窗口的所有消息,但这可以通过更精细的方式和更多的控制来实现。

如果必须在主GUI线程中进行任何处理,并且只想更新接口,则可以使用TWinControl.Repaint方法重绘GUI元素。
如果要使应用程序对用户输入保持响应,则基本上必须使用backgroud / worker线程。

注意:在Delphi中,在主线程中进行任何冗长的处理时,特别是如果涉及等待,您应该定期调用CheckSynchronize,以允许其他任何线程与主线程同步-它们可能(并且可能会)同步否则挂。
VCL仅在应用程序闲置并处理WM_NULL消息时调用此方法(该消息可能无所作为,这也可能会引起一些有趣的副作用)。

08-25 20:02