multithreadingdelphisynchronizationdelphi-2009tmonitor

TMonitor synchronization / Application.ProcessMessages


I'm back with another question concerning threads and synchronization. Imagine a server application that has to perform a lengthy operation and the client wants his GUI to remain responsive while he waits for the server's response. I thought of the following pattern:

TMonitor.Enter (FTCPClient);
try
  WorkerThread := TWorkerThread.Create (SomeLengthyServerOperation);
  while (not WorkerThread.Ready) do
    Application.ProcessMessages;
  DoSometingWithResults (WorkerThread.Result);
  WorkerThread.Free;      
finally
  TMonitor.Exit (FTCPClient);
end;

WorkerThread is a simple class derived from TThread that executes the function passed to its constructor and then terminates (with Ready=True and the result in Result). The presented code is executed whenever a button is clicked.

Now to my question: If I click the button twice very fast, I get some strange errors that look a lot like the communication beetween server and client is somehow mengled, which I wanted to avoid by locking the FTCPClient object. In what thread are the event handlers after Application.ProcessMessages executed? Is the lock of TMonitor per thread? Does this mean that the lock does not work if I use Application.ProcessMessages?

I can't explain it better at the moment. I hope someone gets my point. If not, feel free to ask questions.

EDIT: For the Disabling and Enabling of the button: I don't know anything about the client code. Could be a button event handler, could be something else. Basically I want to hide the locking from the client code.


Solution

  • TMonitor only blocks a different thread from acquiring the lock. What's happening is this: by processing messages from within the lock, you're getting back into the same function in the same thread, which is causing a recursive acquisition of the lock. Your code is then creating a new worker thread, and starting the cycle all over. You could disable the button so that you cannot click it again until the worker thread completes. Be sure you disable the button before you start processing the messages and use another try..finally block to ensure it gets re-enabled. Depending on how the rest of your code is arranged, you may not even need the lock.