Delphi Multi-Threading Message Loop
Solution 1
If I may point to few problems in your code ...
1) You're not checking output of AllocateHwnd. Yes, most probably it will never fail, but still ...
2) AllocateHwnd belogs OUT of try..finally! If it fails, DeallocateHwnd should not be called.
3) AllocateHwnd is not threadsafe. If you call it from multiple threads at the same time, you can run into poblems. Read more.
As Davy said, use MsgWaitForMultipleObjects instead of creating hidden message window. Then use PostThreadMessage to send messages to thread.
If I may put a plug for a totally free product here - use my OmniThreadLibrary instead. Much simpler than messing directly with Windows messaging.
Solution 2
I've had the same problem, and I found out I shouldn't create a hidden window just to recieve messages. Threads already have a message system.
I think that you're creating your windows handle and store it in fHandle, but GetMessage checks your thread's message loop. Therefore the message PostMessage(fHandle, WM_QUIT, 0, 0); is never recieved by the getmesssage.
You can post messages to your thread using PostThreadMessage, and in the thread you use GetMessage(CurrentMessage, 0, 0, 0). The only important difference is that you have to start the message loop from your thread by calling
PeekMessage(CurrentMessage, 0, WM_USER, WM_USER, PM_NOREMOVE);
You should start with this, than do your setup and than start your loop.
The reason why you should start with the peek message is to make sure messages which are sent during the initialization of your threadprocedure are not lost.
The weird thing is, at the moment I can't find the reference where I learned this, but my guess is the newsgroup community.
Atlas
Updated on July 27, 2022Comments
-
Atlas almost 2 years
My application has several threads: 1) Main Thread 2) 2 Sub-Main Threads (each with Message Loop, as shown below), used by TFQM 3) n Worker Threads (simple loop, containing Sleep())
My problem is, when I close my application, the Worker Threads manage to exit properly, but 1 of the 2 Sub-Main Threads hangs (never exits) when I issue WM_QUIT to close them.
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;
-
Atlas over 15 yearsOoops, sorry my first time here. Didn't know about comments.... I'll give it a try. Thanks.
-
med over 15 yearsD2007+, actually. Time to upgrade, then :)
-
Remko over 14 yearsDavy is right: PeekMessage should be used to create the Message Queue
-
mistertodd about 12 yearsYou read it on the MSDN page for
PostThreadMessage
. They even recommend having the main thread wait on an event which the thread sets once it's message has been created.