There is a thread in my Delphi application that has a message-waiting loop. Every time it receives a message, it starts doing some work. Here is the execute procedure of that thread:
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;
Doing some tests using my application I discovered that the GetMessage function is main thread dependent. By this I mean that while the main thread is doing some work, the GetMessage function in my thread does not return even though a message is waiting to be received by it (the message is sent by yet another thread using the PostThreadMessage funciton: PostMessage(MyThreadId, WM_MyMessage, 0, 0)).
Only when the main thread finishes its work or the Application.ProcessMessages method is called, does GetMessage return and my thread starts doing its work. Implementing this kind of inter-thread communication I was sure that my threads would work independently and I would never expect that the reception of messages sent directly to a thread would be dependent on the main thread.
Doing the tests I used the WaitForSingleObject function in the main thread, waiting for an event for a few seconds. This is when I noticed that my thread was not doing any work even though messages were sent to it by another thread. When the WaitForSingleObject function finally finished waiting and the main thread became idle, the GetMessage function in my thread returned.
Could somebody explain me why it works this way? Is there a workaround to that? I would like to make my thread receive messages independently. All my threads are created by the main thread. May this be the reason?
Thanks for your help in advance.
Mariusz.
Mghie, you were absolutely right again (you have helped me with the messaging stuff lately, you might remember). As you suggested, GetMessage returns immediately, but the thread hangs, in fact, on a call to a main window method:
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 is a method of object, declared as 'procedure (EventMask: Cardinal) of object;' (this thread handles serial port events). In this case the FOnCommEventMethod was assigned a procedure belonging to the main form class. When the method is called by my thread, the thread hangs waiting for the main thread to finish its work.
How come? As you can see, I don't use the Synchronize() method to call this procedure. Therefore I would not expect my thread to be synchronizing with the main thread. Does it happen implicitly? BTW, I understand that any GUI components should not be accessed by any other threads but the main one, so the Synchronize method should be used, but I am only doing some quick tests now.
Comming back to the WaitForSingleObject subject, I know I should not use it, but it was only a test thanks to which (coincidentally) I noticed the problem.
Thanks for your help. If you did not help me, I would probably get rid of messaging and use events instead, and finally I would notice that it was not the reason :-).
Only when the main thread finishes its work or the Application.ProcessMessages method is called, does GetMessage return and my thread starts doing its work.
I doubt that this is really what's happening. AFAIK the two message loops should be independent of each other, as long as you don't use other means of synchronizing the threads, like SendMessage(). Are you sure that the thread does indeed block inside of GetMessage() and not inside of Synchronize() (which is using SendMessage() internally)?
Doing the tests I used the WaitForSingleObject function in the main thread, waiting for an event for a few seconds.
You should never use WaitForSingleObject() in the main thread with a timeout longer than say 100 milliseconds, as this will make your GUI appear sluggish. In fact I would advise you to not use it at all in the main thread, because this is simply polling. Post a message from your worker thread instead.