delphi tcollection
Now let’s look at TThread closely.

Creating a descendant of TThread.

TThread is an abstract class that means that you can’t use TThread class itself. You need to create a subclass, which overrides Execute method at least. Each new instance of a subclass object is a new thread of execution. Multiple instances of a TThread derived class make a Delphi application multi-threaded. Delphi documentation notes: “the recommended limit is 16 threads per process on single processor systems”.

TThread virtual and protected methods.

A protected member is visible anywhere in the module where its class is declared and from any descendant class, regardless of the module where the descendant class appears. Protected members are intended for use only in the implementation of derived classes. A virtual method can be redefined in descendant classes, but still be called in the ancestor class. The address of a virtual method isn’t determined at compile time; instead, the object where the method is defined looks up the address at runtime.

Execute method.

Execute method is an abstract method that contains the code which executes when the thread is run. Override Execute and insert the code that should be executed when the thread runs. Execute is responsible for checking the value of the Terminated property to determine if the thread needs to exit.

DoTerminate method.

Current implementation of DoTerminate method generates an OnTerminate event in the context of main VCL thread using Synchronize. Method is called just after Execute returns. DoTerminate is virtual method and can be overridden in subclass.

Terminated property.

Indicates that the thread has been asked to terminate. The Terminate method sets the Terminated property to True. The thread’s Execute method and any methods that Execute calls should check Terminated periodically and exit when it’s True.

Program example.

type
TForm1 = class(TForm)
Memo1: TMemo;
GroupBox1: TGroupBox;
seTimeToWork: TSpinEdit;
Label1: TLabel;
btnCreate: TButton;
btnTerminate: TButton;
procedure FormShow(Sender: TObject);
procedure btnCreateClick(Sender: TObject);
procedure btnTerminateClick(Sender: TObject);
private
FThread:TThread;
procedure EnableButtons;
procedure OnTerminate(Sender:TObject);
end;

TMyThread=class(TThread)
private
FTimeToWork:integer;
protected
procedure Execute;override;
public
constructor Create(TimeToWork:integer);
end;
var
Form1: TForm1;
implementation

{$R *.DFM}

// TMyThread

constructor TMyThread.Create(TimeToWork: integer);
begin
FTimeToWork:=TimeToWork;
inherited Create(True);
end;
procedure TMyThread.Execute;
var
T:Integer;
begin
t:=FTimeToWork;
Form1.Memo1.Lines.Add('Begin execution');
while not Terminated and (t>0) do
begin
Form1.Memo1.Lines.Add(format('Remaining %5.2f%%',[t/FTimeToWork*100]));
Sleep(500);
dec(t,500);
end;
if Terminated then
Form1.Memo1.Lines.Add('Terminated by user');
Form1.Memo1.Lines.Add('Finish execution');
end;
// TForm1
procedure TForm1.EnableButtons;
begin
btnCreate.Enabled:=not Assigned(FThread);
btnTerminate.Enabled:= Assigned(FThread);
end;
procedure TForm1.FormShow(Sender: TObject);
begin
EnableButtons;
end;
procedure TForm1.btnCreateClick(Sender: TObject);
begin
FThread:=TMyThread.Create(seTimeToWork.Value);
FThread.OnTerminate:=OnTerminate;
EnableButtons;
FThread.Resume;
end;
procedure TForm1.btnTerminateClick(Sender: TObject);
begin
FThread.Terminate;
end;
procedure TForm1.OnTerminate(Sender: TObject);
begin
FThread:=nil;
EnableButtons;
end;
end.

Code explanation.

It’s very simple program. Source code contains two classes:

TForm1 class.

TForm1 class inherited from TForm represents the main application form that owns Memo, two buttons and spin-edit controls. In addition, there are some event handlers. Procedure btnCreateClick() is called when user clicks “Create” button. It creates new instance of TMyThread object and stores pointer in FThread field. Pressing “Terminate” button generates btnTerminateClick() event that calls Terminate method of thread object signaling termination request. Note that only one thread object instance referenced by FThread field is created at one time. “Create” button is disabled when the thread object instance exists (FThread<>nil) and vice versa enabled if there are no thread object (Fthread = nil). OnTerminate event occurs when the thread finishes its execution. It permits further calls of btnCreateClick() by enabling “Create” button, so user can create one more thread.

TMyThread class.

TMyThread class inherited from TThread represents new thread. TmyThread.Execute simulates some “work” during user-determined time and outputs percentage of “work” done into memo control. This method periodically checks Terminated property and exits when it’s True. Note that Terminate method of TThread does not terminate thread immediately. It only stores true in some TThread object private field that can be accessed through Terminated property. Also note that Terminated property is protected, that means that only TThread subclasses can access it.