Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi Multi-Threading Message Loop

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;
like image 546
Atlas Avatar asked Oct 23 '08 13:10

Atlas


1 Answers

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.

like image 94
gabr Avatar answered Sep 25 '22 06:09

gabr