Multithreading is one of those operating systems feaures that make your programs work in a more efficient way and give your users a better interactive interface. However they are not used by all developers.
In this article I will focus on some important points you must have in mind when using threads on Delphi.
How to create them
There are two simple steps to accomplish it:
- Create a new class that inherits from TThread and
- Override the Execute method.
TMyThread = class(TThread) public procedure Execute; override; end; procedure TMyThread.Execute; begin DoSomeWork(); //When the procedure ends, the thread ends. end;
How to call them
The default constructor accepts a parameter that instructs the new thread to start immediatly after construction or remain suspended. Remember you can override constructors, but make sure you call inherited inside it in order to execute the parent class constructor too.
The following snippet will create a thread everytime StartButton is clicked.
procedure TForm.StartButtonClick(Sender: TObject); begin TMyThread.Create(false); end;
FreeOnTerminate is an important property. When it is true, it will free all related resources when the thread execution finishes.
If you need to access some of your thread’s resources after finalization, like property values, set this property to false. In this case remember to call your thread’s free procedure.
You can change your thread priority by changing the Priority property to any of the following values: tpIdle, tpLowest, tpNormal, tpHigher, tpHighest, tpTimeCritical.
User Interface Synchronization
UI synchronization must be done through calls to Synchronize. This procedure sends a message to the main thread’s message queue instructing it to execute the given procedure. When the main queue finds this message, it will pause the calling thread until the code finishes executing.
Synchronize uses Windows’ SendMessage API function to put the message in the main thread’s queue. Synchronize is a thread safe procedure and you should use it to make any UI update.
procedure TMyThread.Execute; begin while something do begin DoSomeWork(); Synchronize(UpdateUI); end end; procedure TForm.UpdateUI; begin // Update the UI like progress bars, etc. end;
Using Global Variables and VCL components
Yes, you have access to global variables (usually from your main form) to accomplish UI update. When calling Synchronize, you send two parameters:
- The calling thread and
- The procedure to be called by the main thread
Since the procedure to be called (the second one in the previous list) is executed by the main thread, then you can have access to all variables and VCL components used in your form.
To perform asynchronous calls you have to use the Queue procedure, which uses the Windows’ PostMessage API function.