我的Delphi应用程序中有一个线程有一个消息等待循环。每次收到消息时,它都会开始做一些工作。这是该线程的执行过程:

procedure TMyThread.Execute;
begin
  while GetMessage(Msg, 0, 0, 0) and not Terminated do
  begin
    {thread message}
    if Msg.hwnd = 0 then
    begin
      ...
    end
    else
      DispatchMessage(Msg);
  end;
end;

使用我的应用程序进行一些测试我发现GetMessage函数是主线程依赖的。我的意思是,当主线程正在做一些工作时,我的线程中的GetMessage函数不会返回,即使消息等待它被接收(消息由另一个线程使用PostThreadMessage函数发送:PostMessage( MyThreadId,WM_MyMessage,0,0))。

只有当主线程完成其工作或调用Application.ProcessMessages方法时,GetMessage才会返回并且我的线程开始执行其工作。实现这种线程间通信我确信我的线程将独立工作,我永远不会期望直接发送到线程的消息的接收将依赖于主线程。

进行测试我在主线程中使用了WaitForSingleObject函数,等待事件几秒钟。这是当我注意到我的线程没有做任何工作,即使消息是由另一个线程发送给它。当WaitForSingleObject函数最终完成等待并且主线程变为空闲时,我的线程中的GetMessage函数返回。

有人可以解释一下为什么它会这样运作吗?有解决方法吗?我想让我的线程独立接收消息。我的所有线程都是由主线程创建的。这可能是原因吗?

提前感谢您的帮助。

马里乌什。


Mghie,你再次绝对正确(你最近帮助我了解消息,你可能还记得)。正如你的建议,GetMessage立即返回,但实际上,线程在调用主窗口方法时挂起:

procedure TMyThread.Execute;
begin
  while GetMessage(Msg, 0, 0, 0) and not Terminated do
  begin
    {thread message}
    if Msg.hwnd = 0 then
    begin
      ...
      if Assigned(FOnCommEventMethod) then
        FOnCommEventMethod(FCommEventsQueueItem);
      ...
    end
    else
      DispatchMessage(Msg);
  end;
end;

FOnCommEventMethod是一个对象的方法,声明为'procedure(EventMask:Cardinal)of object;' (此线程处理串行端口事件)。在这种情况下,为FOnCommEventMethod分配了一个属于主窗体类的过程。当我的线程调用该方法时,线程会挂起,等待主线程完成其工作。

为什么?如您所见,我不使用Synchronize()方法来调用此过程。因此我不希望我的线程与主线程同步。是否隐含发生?顺便说一下,我知道任何其他线程都不应该访问任何GUI组件而应该是主要的,所以应该使用Synchronize方法,但我现在只做一些快速测试。

回到WaitForSingleObject主题,我知道我不应该使用它,但这只是一个测试,感谢(巧合)我注意到了这个问题。

感谢您的帮助。如果你没有帮助我,我可能会摆脱消息传递并使用事件,最后我会注意到它不是原因: - )。

有帮助吗?

解决方案

  

只有当主线程完成其工作或调用Application.ProcessMessages方法时,GetMessage才会返回并且我的线程开始执行其工作。

我怀疑这是真的发生了什么。 AFAIK这两个消息循环应该是相互独立的,只要你不使用其他同步线程的方法,比如 SendMessage()。您确定该线程确实阻止了 GetMessage()内部而不是 Synchronize()(在内部使用 SendMessage()内部)?

  

进行测试我在主线程中使用WaitForSingleObject函数,等待事件几秒钟。

你不应该在主线程中使用 WaitForSingleObject(),超时时间超过100毫秒,因为这会使你的GUI显得迟钝。事实上,我建议你不要在主线程中使用它,因为这只是简单的轮询。而是从您的工作线程发布消息。

其他提示

您可以为线程创建消息队列。只需在您的主题中执行以下代码:

MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
SetEvent(messageQueueReady);
while (GetMessage(&msg, NULL, 0, 0)) 
{
    ...// do message processing here
}

对PeekMessage的调用强制操作系统为您的线程创建一个新的消息队列。您必须确保同步这一点,即您必须等待(例如通过WaitForSingleObject)才能在将消息发布到此线程之前成功调用(例如,通过PostThreadMessage)。这就是上面示例中调用SetEvent API的原因。

修改:对于C中的示例感到抱歉,希望对您有用。

请参阅 http:// groups.google.com/group/borland.public.delphi.language.delphi.win32/browse_thread/thread/cf368834a606321b

请求蒸馏,留下魔鬼隐藏的许多粗糙细节:主要(或VCL)线程在Delphi中是特殊的,因为引擎盖下的许多东西都不是线程安全的,并且它拥有它们。像消息循环这样的事情因为与引擎盖下的VCL线程同步的事情而结束等待。很多人都有这方面的理论。看起来效果最好的是让VCL线程尽可能轻/响应,以尽量减少等待。每个人都非常赞同这一点。有些人对其他可能有效的事情有所了解,但其他人认为他们只是在惹麻烦。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top