Application.ProcessMessages 挂起?
我的单线程 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 例程在我的脑海中浮现出一些没有意义的东西。
有什么一般性建议吗?
我很惊讶地看到在开发的这个阶段出现了这种问题!
my single threaded delphi 2009 app (not quite yet complete) has started to have a problem with Application.ProcessMessages hanging. my app has a TTimer object that fires every 100 ms to poll an external device. i use Application.ProcessMessages to update the screen when something changes so the app is still responsive.
one of these was in a grid OnMouseDown event. in there, it had an Application.ProcessMessages that essentially hung. removing that was no problem except that i soon discovered another Application.ProcessMessages that was also blocking.
i think what may be happening to me is that the TTimer is--in the app mode i'm currently debugging--probably taking too long to complete. i have prevented the TTimer.OnTimer event hander from re-entering the same code (see below):
procedure TfrmMeas.tmrCheckTimer(Sender: TObject);
begin
if m_CheckTimerBusy then
exit;
m_CheckTimerBusy:=true;
try
PollForAndShowMeasurements;
finally
m_CheckTimerBusy:=false;
end;
end;
what places would it be a bad practice to call Application.ProcessMessages? OnPaint routines springs to mind as something that wouldn't make sense.
any general recommendations?
i am surprised to see this kind of problem arise at this point in the development!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我对
TApplication.ProcessMessages
的建议是永远不要使用它 - 根本没有放置它的好点。想象一下调用它会做什么:您的应用程序运行一个消息循环 - 其中 Windows 消息(由操作系统、其他应用程序、您的应用程序等生成)被顺序处理 - 并且在其中一个消息处理的中间,您只需再次重新运行整个消息循环,无法控制将处理哪些消息、将有多少消息、是否有任何消息将进入其自己的消息循环......以及它们是否有任何重入问题。这就是我所说的自招麻烦。
有时有很好的理由来处理一些窗口消息(特别是不挂起其他线程),或者处理所有定向到的消息一个特定的窗口,但这可以通过更微妙的方式和更多的控制来完成。
如果您必须在主 GUI 线程中进行任何处理,并且您只想更新界面,您可以使用
TWinControl.Repaint
方法重绘 GUI 元素。如果您想让应用程序响应用户输入,您基本上必须使用后台/工作线程。
注意:在Delphi中,当在主线程中进行任何长时间的处理时,特别是如果涉及等待,您应该定期调用
CheckSynchronize
,以允许任何其他线程与主线程同步 - 它们可能(并且可能会)否则挂起。VCL 仅在应用程序空闲时以及处理 WM_NULL 消息时调用此函数(假设不执行任何操作,这也可能会导致一些有趣的副作用)。
My recommendation regarding
TApplication.ProcessMessages
is to never ever use it - there simply isn't a good point to place it.Imagine what calling it does: your application runs a message loop - where the windows messages (produced by OS, other apps, your app etc) are sequentially processed - and there, in the middle of one of the message-processings, you just re-run the whole message loop again, without having control over what messages will be processed, how much of them there will be, if any of the messages will enter its' own message loop... and if they have any reentrancy problems or not. That's what I call inviting trouble.
There are sometimes good reasons to process some windows messages (particularry to not hang other threads), or to process all messagess directed to a particular window, but this may be accomplished in more subtle ways, with more control.
If you have to do any processing in the main GUI thread, and you just want to update the interface, you may use the
TWinControl.Repaint
method to redraw the GUI elements.If you want to keep the app responsive to user input, you basically have to use backgroud/worker threads.
Notice: in Delphi, while doing any lenghty processing in the main thread, especcially if waiting is involved, you are supposed to call
CheckSynchronize
periodically, to allow any other threads to synchonize with the main thread - they may (and probably will) hang otherwise.VCL calls this only when the app goes idle and when it processes the
WM_NULL
message (that is supossed to do nothing, which may cause some interesting side-effects too).谢谢大家的意见/建议。
在这里,我制作了一个测试应用程序,它有一个计时器例程,该例程花费的时间比设置的时间间隔更长。当我按下button1时,Application.ProcessMessages挂起。我现在的解决方案是在计时器例程中禁用计时器。
稍后我们计划将“设备通信”放在一个线程中。
谢谢你!
议员
thank you all for your comments/suggestions.
here i made a test app that has a timer routine that takes longer than the interval it is set for. when i push button1, Application.ProcessMessages hangs. my solution for now is to disable the timer during the timer routine.
later we plan to put the "device communications" in a thread.
thank you!
mp
使用 madExcept 你就会看到死锁在哪里。
Use madExcept and you will see where is the deadlock.
严重依赖基于计时器的逻辑似乎很糟糕,并且您明白,正如您所说,您计划在将来使用线程。
以下是代码的进展:
让我们放大一点,在间隔为 100 毫秒的计时器上,考虑最坏的情况:
你能看到... 你能看到... 你能看到... 这里的问题吗?
瓦
It seems terrible style to rely heavily on timer-based logic, and you understand that as you say you are planning to use threads in the future.
Here's the progression in your code:
Let's zoom in a little, on a timer with 100 msec interval, for a worst case:
Can you see the... Can you see the.... Can you see the..... problem here?
W