Parallel Programming with the TTask Class — Delphi Source Code Collection
This article explains how to use the TTask class in Delphi for parallel programming, using a sample source code that performs prime number detection.
In this example, 100 TTask instances are used to run prime checks in 100-way parallel execution.
Screen Layout
Launch the Delphi IDE and select "File" => "Windows VCL Application – Delphi" to create a new project and its initial form.
From the "Palette" pane in the lower-right corner, drag and drop the following components onto the form:
- TButton x 1
- TMemo x 1
Writing the Source Code
Press F12 to switch to the Code Editor, then copy and paste the following source code.
Press F12 again to return to the Form Designer, open the [Events] tab in the Object Inspector at the lower-left pane, select Button1, and set Button1.OnClick to Button1Click.
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
System.Threading, System.SyncObjs, System.Math;
type
// Using the TTask class from the parallel programming library
// If Num is a prime number, add the result to fAnswers
TPrimeTest=class(TTask, ITask)
private
fNum:INT64;
fAnswers:TStringList;
public
constructor Create(Num:Int64; Answers:TStringList);
procedure TaskStart;
end;
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TPrimeTest }
constructor TPrimeTest.Create(Num: Int64; Answers: TStringList);
begin
//Store parameters in private fields
fNum:=Num;
fAnswers:=Answers;
//Call the parent class constructor
inherited Create(
nil, nil,
procedure
begin
Self.TaskStart;
end,
nil, nil, []
);
end;
procedure TPrimeTest.TaskStart;
var i,m:Int64;
flag:Boolean;
st:String;
begin
st:='';
if fNum<2 then
begin
exit;
end
else if (fNum=2) or (fNum=3) then
begin
st:=Format('%d is a prime number',[fNum]);
end
else
begin
m:=Trunc(Sqrt(fNum));
i:=2;
flag:=True;
while i<=m do
begin
if fNum Mod i =0 then
begin
flag:=False; //Not a prime number
break;
end;
inc(i);
end;
if flag then
st:=Format('%d is a prime number',[fNum]);
end;
if st<>'' then
begin
//Protect shared object access (lock)
System.MonitorEnter(fAnswers);
try
// Add result to the list
fAnswers.Add(st);
finally
//Release lock
System.MonitorExit(fAnswers);
end;
end;
end;
{TForm1}
procedure TForm1.Button1Click(Sender: TObject);
const
//Execute up to 100 tasks in parallel
MaxTaskCount:Integer = 100;
//Find prime numbers between 10000 and 50000
FromNumber:Integer=10000;
ToNumber :Integer=50000;
var i,n:Int64;
Tasks:TArray<ITask>;
TaskCount:Integer;
Answers:TStringList;
begin
Memo1.ScrollBars:=ssBoth;
Answers:=TStringList.Create;
try
n:=FromNumber;
while n<=ToNumber do
begin
if (n+MaxTaskCount-1)>ToNumber then
TaskCount:=ToNumber-n+1
else
TaskCount:=MaxTaskCount;
//Prepare tasks for parallel execution
SetLength(Tasks,TaskCount);
for i := Low(Tasks) to High(Tasks) do
begin
Tasks[i]:=TPrimeTest.Create(n,Answers) as ITask;
inc(n);
end;
//Start all tasks
for i := Low(Tasks) to High(Tasks) do Tasks[i].Start;
// Wait until all tasks are completed
// The order of start and completion is not guaranteed
TTask.WaitForAll(Tasks);
end;
//Memo1.Lines.BeginUpdate;
Memo1.Lines.Assign(Answers);
//Memo1.Lines.EndUpdate;
finally
Answers.Free;
end;
end;
end.
Running the Program
Click the Run button in the IDE to start the application.
When you click Button1, the program will search for prime numbers between 10,000 and 50,000 and display the results in Memo1.
