Question

I know Synchronize must be used in the Execute procedure, but should it be used in Create and Destroy methods too, or is it safe to do whatever I want?

Was it helpful?

Solution 2

There is a need to use Synchronize() when the code is executing outside of the context of the main (GUI) thread of the application. Therefore the answer to your question depends on whether the constructor and destructor are called from that thread or not.

If you are unsure you can check that by comparing the result of the Windows API function GetCurrentThreadId() with the variable MainThreadID - if they equal the code executes in the context of the main thread.

Threads that have FreeOnTerminate set will have their destructor called from another thread context, so you would need to use Synchronize() or Queue(). Or you use the termination event the VCL already provides, I believe it is executed in the main thread, but check the documentation for details.

OTHER TIPS

I know Synchronize must be used in the Execute procedure.

That is somewhat vague. You need to use Synchronize when you have code that must execute on the main thread. So the answer to whether or not you will need to use Synchronize depends crucially on what the code under consideration actually does. The question that you must ask yourself, and which is one that only you can answer, is do you have code that must run on the main thread?

As a general rule it would be considered prudent for you not to need to call Synchronize outside the Execute method. If you can find a way to avoid doing so then that would be wise. Remember that the ideal scenario with threads is that they never need to block with Synchronize if at all possible.


You might also wish to consider which thread executes the constructor and destructor.

The constructor Create runs in the thread that calls it. It does not run in the newly created thread. Therefore it is unlikely that you would need to use Synchronize there.

The destructor Destroy runs in the thread that calls it. Typically this is the thread that calls Free on the thread object. And usually that would be called from the same thread that originally created the thread. The common exception to that is a FreeOnTerminate thread which calls Free from the thread.

First of all, you don't want to call Synchronize() unnecessarily, because that simply defeats the purpose of using a thread. So the decision should be based on whether: (a) it's possible to encounter race conditions with shared data. (b) you'll be using VCL code which usually has to run on the main thread.

It's unlikely you would need to synchronise in the constructor because TThread instances are usually created from the main thread already. (The exception being if you're creating some TThread's from another child thread.)

NOTE: It won't cause any harm though because Synchronize() already checks if you're on the main thread and will call the synchronised method immediately if you are.

class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord; QueueEvent: Boolean = False);
var
  SyncProc: TSyncProc;
  SyncProcPtr: PSyncProc;
begin
  if GetCurrentThreadID = MainThreadID then
    ASyncRec.FMethod

As for the destructor there are 3 usage patterns:

  • The TThread instances destroys itself.
  • Another thread (possibly the main thread) can WaitFor the instance to finish, then destroy it.
  • You can intercept the OnTerminate event. This is fired when the instance is finished, and you could then destroy it.

NOTE: The OnTerminate event will already be synchronised.

procedure TThread.DoTerminate;
begin
  if Assigned(FOnTerminate) then Synchronize(CallOnTerminate);
end;

Given the above, the only time you might need to synchronise is if the thread self-destructs.

However, I'd advise that you rather avoid putting code into your destructor that might need to be synchronised. If you need some results of a calculation from your thread instance, OnTerminate is the more appropriate place to get this.

To add to what has been said in other answers...

You never need to use Synchronize at all. Synchronize may be useful, however, in the following circumstance:

  1. In the context of your thread you need to execute code that touches objects that have affinity to the main thread.
  2. You require your thread to block until that code has been executed.

Even in that case, there are other ways to achive the same goal, but Synchronize provides a convenient way to satisfy those two needs. If you need only one of those two items, there are better strategies available.

On topic #1, the obvious objects are user interface objects. These are objects that have thread affinity to the main thread simply by virtue of the fact that the main thread is continually reading and writing the properties of those objects (not the least because it needs to paint them to the screen, etc) and it does so at its own convenience. This means that your thread cannot safely access those components with a guarantee that the main thread will not also be accessing or modifying them at the same time. In order to prevent corruption, the thread has to pass the work to the main thread (since the main thread can only do one thing at a time and can't, obviously, interfere with itself). Synchronize simply places the work onto the main thread's queue and waits until the main thread gets around to completing it before returning.

This gets to point #2. Do you need to (or, equally, can you afford to) wait around until the main thread finishes the work? There are three cases and two options.

  1. Yes, you can or must wait. (Synchronize is a good fit)
  2. No, you cannot wait. (Synchronize is not a good fit)
  3. Don't care. (Synchronize is easy, so it's a sensible option)

If you are simply updating a status display that will soon be overwritten anyway and your thread has more pressing issues, then it's probably sensible to just post a message to the main thread and carry on doing things, for example. If your thread is just waiting around doing nothing, mostly, and it's not worth the time to code anything more sophisticated, then Synchronize is just fine, and it can be replaced with something better if needs dictate so in the future.

As others have said, it really depends on what you are doing. The more important question, I think, at least conceptually, is to sort out when you need to worry about concurrency and when you don't. Any time you have more than one thread that requires access to a single resource you need to use some sort of mechanism to coordinate that access to avoid the threads crashing into each other. Synchronize is one of those methods, but it not the least nor the last of them.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top