TThread 在 Delphi 2006 控制台应用程序中的工作方式是否不同?
我们有一个相当成熟的 COM dll,我们使用 DUnit 对其进行测试。 我们最近的测试之一创建了一些线程,并从这些线程测试对象。 当使用 GUI 前端运行测试时,此测试工作正常,但在作为控制台应用程序运行时挂起。 这是我们在测试中的快速伪视图,
SetupTest;
fThreadRefCount := 0; //number of active threads
Thread1 := TMyThread.Create(True);
Inc(fThreadRefCount);
Thread1.OnTerminate := HandleTerminate; //HandleOnTerminate decrements fThreadRefCount
Thread3 := TMyThread.Create(True);
Inc(fThreadRefCount);
Thread2.OnTerminate := HandleTerminate; //HandleOnTerminate decrements fThreadRefCount
Thread3 := TMyThread.Create(True);
Inc(fThreadRefCount);
Thread3.OnTerminate := HandleTerminate; //HandleOnTerminate decrements fThreadRefCount
Thread1.Resume;
Thread2.Resume;
Thread3.Resume;
while fThreadRefCount > 0 do
Application.ProcessMessages;
我尝试在 OnExecute 中不执行任何操作,因此我确信这不是我正在测试的实际代码。 在控制台中,fThreadRefCount永远不会递减,而如果我将它作为GUI应用程序运行,那就没问题了!
据我所知,OnTerminate 事件只是没有被调用。
We have a pretty mature COM dll, which we test using DUnit. One of our recent tests creates a few threads, and tests the object from those threads. This test works fine when running the test using the gui front-end, but hangs when running as a console application. Here's a quick pseudo view of what we have in the test
SetupTest;
fThreadRefCount := 0; //number of active threads
Thread1 := TMyThread.Create(True);
Inc(fThreadRefCount);
Thread1.OnTerminate := HandleTerminate; //HandleOnTerminate decrements fThreadRefCount
Thread3 := TMyThread.Create(True);
Inc(fThreadRefCount);
Thread2.OnTerminate := HandleTerminate; //HandleOnTerminate decrements fThreadRefCount
Thread3 := TMyThread.Create(True);
Inc(fThreadRefCount);
Thread3.OnTerminate := HandleTerminate; //HandleOnTerminate decrements fThreadRefCount
Thread1.Resume;
Thread2.Resume;
Thread3.Resume;
while fThreadRefCount > 0 do
Application.ProcessMessages;
I have tried doing nothing in the OnExecute, so I'm sure it's not the actual code I'm testing. In the console, fThreadRefCount never decrements, while if I run it as a gui app, it's fine!
As far as I can see, the OnTerminate event is just not called.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要提供更多数据。
请注意,
OnTerminate
是通过Synchronize()
调用的,这需要在某个时刻调用CheckSynchronize()
。Application.ProcessMessages()
通常会执行此操作,但根据 VCL 的初始化方式,Synchronize()
机制可能尚未完全连接在一起控制台应用程序。无论如何,这个程序在我的机器上按预期工作:
You need to provide more data.
Note that
OnTerminate
is called viaSynchronize()
, which requires a call toCheckSynchronize()
at some point somewhere.Application.ProcessMessages()
normally does this, but depending on how the VCL has been initialized, it's possible that theSynchronize()
mechanism hasn't been fully hooked together in a Console application.In any case, this program works as expected on my machine:
正如 Barry 正确指出的那样,除非调用
CheckSyncronize()
,否则不会处理Synchronize()
,并且如果不处理Synchronize()
,那么OnTerminate
事件不会被触发。似乎发生的情况是,当我作为控制台应用程序运行单元测试时,消息队列上没有消息,因此从
Application 调用的
,永远无法调用Application.ProcessMessage()
.ProcessMessages()CheckSynchronize()
。我现在通过将循环更改为以下方式解决了问题:
它现在可以在控制台和 GUI 模式下工作。
整个
WakeupMainThread
钩子似乎设置正确。 正是这个钩子发布了触发CheckSynchronize()
的WM_NULL
消息。 它只是在控制台应用程序中没有达到那么远。更多调查
因此,
Synchronize()
确实被调用。DoTerminate()
调用Synchronize(CallOnTerminate)
但其中有一行:它只是永远等待。
因此,虽然我的上述修复有效,但还有更深层次的内容!
As Barry rightly pointed out, unless
CheckSyncronize()
is called,Synchronize()
is not processed, and ifSynchronize()
is not processed, then theOnTerminate
event is not fired.What seems to be happening is that when I run my unit tests as a Console application, there are no messages on the message queue, and thus
Application.ProcessMessage()
, which is called fromApplication.ProcessMessages()
, never gets to callCheckSynchronize()
.I've now solved the problem by changing the loop to this:
It now works in both Console and GUI modes.
The whole
WakeupMainThread
hook seems to be setup properly. It's this hook which posts theWM_NULL
message that triggers theCheckSynchronize()
. It just doesn't get that far in the Console app.More Investigation
So,
Synchronize()
does get called.DoTerminate()
callsSynchronize(CallOnTerminate)
but there's a line in there:which just waits forever.
So, while my fix above works, there's something deeper to this!