当前位置:  开发笔记 > 开发工具 > 正文

Delphi多线程消息循环

如何解决《Delphi多线程消息循环》经验,为你挑选了3个好方法。

我的应用程序有几个线程:1)主线程2)2个子主线程(每个都有消息循环,如下所示),由TFQM使用3)n工作线程(简单循环,包含Sleep())

我的问题是,当我关闭我的应用程序时,工作线程设法正常退出,但当我发出WM_QUIT关闭它们时,2个子主线程中的一个挂起(从不退出).


procedure ThreadProcFQM(P: Integer); stdcall;
var
  Msg: TMsg;
 _FQM: TFQM;
begin
  _FQM := Ptr(P);
  try
    _FQM.fHandle := AllocateHwnd(_FQM.WndProc);

    while GetMessage(Msg, 0, 0, 0) do
    begin
      TranslateMessage(Msg);
      DispatchMessage(Msg);
    end;

  finally
    DeallocateHWnd(_FQM.fHandle);
    SetEvent(_FQM.hTerminated);
  end;
end;

procedure TFQM.Stop;
begin
  PostMessage(fHandle, WM_QUIT, 0, 0);

  WaitForSingleObject(hTerminated, INFINITE);
  if hThread <> INVALID_HANDLE_VALUE then
  begin
    CloseHandle(hThread);
    hThread := INVALID_HANDLE_VALUE;
  end;
end;

gabr.. 11

如果我在你的代码中指出几个问题......

1)您没有检查AllocateHwnd的输出.是的,很可能它永远不会失败,但仍然......

2)AllocateHwnd belogs out of try..finally!如果失败,则不应调用DeallocateHwnd.

3)AllocateHwnd不是线程安全的.如果你同时从多个线程调用它,你可能会遇到问题.阅读更多.

正如戴维所说,使用MsgWaitForMultipleObjects而不是创建隐藏的消息窗口.然后使用PostThreadMessage向线程发送消息.

如果我可以在这里插一个完全免费的产品 - 请使用我的OmniThreadLibrary.比直接使用Windows消息传递更简单.



1> gabr..:

如果我在你的代码中指出几个问题......

1)您没有检查AllocateHwnd的输出.是的,很可能它永远不会失败,但仍然......

2)AllocateHwnd belogs out of try..finally!如果失败,则不应调用DeallocateHwnd.

3)AllocateHwnd不是线程安全的.如果你同时从多个线程调用它,你可能会遇到问题.阅读更多.

正如戴维所说,使用MsgWaitForMultipleObjects而不是创建隐藏的消息窗口.然后使用PostThreadMessage向线程发送消息.

如果我可以在这里插一个完全免费的产品 - 请使用我的OmniThreadLibrary.比直接使用Windows消息传递更简单.



2> Davy Landman..:

我遇到了同样的问题,我发现我不应该创建一个隐藏的窗口来接收消息.线程已经有一个消息系统.

我认为您正在创建Windows句柄并将其存储在fHandle中,但GetMessage会检查您的线程的消息循环.因此消息PostMessage(fHandle,WM_QUIT,0,0); getmesssage永远不会收到.

您可以使用PostThreadMessage将消息发布到您的线程,并在线程中使用GetMessage(CurrentMessage,0,0,0).唯一重要的区别是你必须通过调用从线程启动消息循环

PeekMessage(CurrentMessage, 0, WM_USER, WM_USER, PM_NOREMOVE);

你应该从这开始,而不是你的设置,而不是开始你的循环.

你应该从peek消息开始的原因是确保在初始化threadprocedure期间发送的消息不会丢失.

奇怪的是,目前我无法找到我所学到的参考资料,但我的猜测是新闻组社区.



3> 小智..:

1)您的线程中不需要AllocateHwnd.第一次调用GetMessage将为该线程创建一个单独的消息队列.但是为了向线程发送消息,你应该使用PostThreadMessage函数.

请注意,在调用PostThreadMessage时,仍无法创建队列.我经常使用建筑:

while not PostThreadMessage(ThreadID, idStartMessage, 0, 0) do
  Sleep(1);

确保创建消息队列.

2)为了终止线程循环,我定义了自己的消息:

  idExitMessage = WM_USER + 777; // you are free to use your own constant here

3)不需要单独的事件,因为您可以将线程句柄传递给WaitForSingleObject函数.所以,你的代码看起来像:

  PostThreadMessage(ThreadID, idExitMessage, 0, 0);
  WaitForSingleObject(ThreadHandle, INFINITE);

考虑到ThreadID和ThreadHandle是不同的值.

4)因此,您的ThreadProc将如下所示:

procedure ThreadProcFQM; stdcall;
var
  Msg: TMsg;
begin
  while GetMessage(Msg, 0, 0, 0) 
    and (Msg.Message <> idExitMessage) do
  begin
    TranslateMessage(Msg);
    DispatchMessage(Msg);
  end;
end;

推荐阅读
mobiledu2402852357
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有