Synchronize and Queue with Parameters

In Delphi’s TThread class there is Synchronize to call a method in the context of the GUI thread. This is necessary in case, for example, you want to update a progressbar or a status label in a form, because the VCL is not thread safe. While Synchronize is a blocking method (i.e. the thread code continues when the GUI thread has finished the method call), recent versions of Delphi introduced a non-blocking Queue method.

The drawback of using Synchronize is that it is very cumbersome to handle parameters during such a call. The standard solution is to use fields in the TThread descendant holding the parameters during Synchronize, but this won’t work properly with Queue. As Queue is non-blocking there might be multiple calls to Queue waiting to be processed, which often cannot share the same field. Worse, using Queue access to these fields have to be thread safe, too. The queuing thread may just set this field for the next call to Queue while a previous Queue call is executed in the main thread just using this field. As this problem doesn’t exist with Synchronize, switching from Synchronize to Queue just has to be done more careful.

One way to deal with parameters for Synchronize is the use of Anonymous Methods. There is an overloaded version of Synchronize and Queue taking a TThreadProcedure as parameter:

A simple example for a parametrized call to Synchronize could be like this:

The magic is that the Anonymous Method captures the variable PercentComplete. Thus it will be totally safe to use Queue instead of Synchronize here.

I’m using a little trick here to ensure that the critical code is called inside the GUI thread without having a separate method. The ID of the GUI thread is stored in MainThreadID, so I just check if the result of the function GetCurrentThreadID matches this value and call Synchronize otherwise.

One note using Queue: when the thread is freed, all pending Queue calls are removed. So if your code depends on all these calls being handled in the GUI thread you have to make sure that the thread instance lives at least that long.

Author: Uwe Raabe

Addicted to Pascal/Delphi since the late 70's

12 thoughts on “Synchronize and Queue with Parameters”

  1. Nice reference article.
    There is another way of getting rid of the thread synchronization problem: using a stateless design.
    For instance, the approach of our RESTful framework allow to have the main Client thread refreshing its content from the server. No Synchronize to call by hand: just a timer to refresh the Grids and report on screen, when the data has been refreshed on the server side, from any other client. Just like a Web 2.0 app, but for a Delphi client. Best part of both worlds…

  2. About the “if GetCurrentThreadId = MainThreadID then” trick: the Delphi RTL already does this. When you use .Synchronize and .Queue in your main thread, Delphi will directly execute it:

    1. I didn’t claim to be the inventor of that trick – I’m only using it. The code tries to emphasize which part of the code is definitely executed in the main thread context and which is not.

      1. I think what André wanted to say was that you don’t even have to use that trick because the RTL-implementation of TThread.Synchronize already does exactly that.

  3. I’m using queue (fifo list) to passing parameters. Checking length of this list allows us to terminate thread only after execution of all calls via Queue method.

Comments are closed.