我的应用程序有几个线程: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)您没有检查AllocateHwnd的输出.是的,很可能它永远不会失败,但仍然......
2)AllocateHwnd belogs out of try..finally!如果失败,则不应调用DeallocateHwnd.
3)AllocateHwnd不是线程安全的.如果你同时从多个线程调用它,你可能会遇到问题.阅读更多.
正如戴维所说,使用MsgWaitForMultipleObjects而不是创建隐藏的消息窗口.然后使用PostThreadMessage向线程发送消息.
如果我可以在这里插一个完全免费的产品 - 请使用我的OmniThreadLibrary.比直接使用Windows消息传递更简单.
我遇到了同样的问题,我发现我不应该创建一个隐藏的窗口来接收消息.线程已经有一个消息系统.
我认为您正在创建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期间发送的消息不会丢失.
奇怪的是,目前我无法找到我所学到的参考资料,但我的猜测是新闻组社区.
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;