TTaskクラスを使って並列プログラミング ~Delphiソースコード集
DelphiでTTaskクラスを使って並列プログラミングする方法を、素数判定のサンプルソースコードで解説します。
このサンプルソースコードでは10個のTTaskを使って10並列で素数判定を行います。
画面設計
Delphi IDEを起動し、「ファイル」⇒「Windows VCLアプリケーション -Delphi」をクリックしてプロジェクトと初期フォームを作成します。
右下ペインにある「パレット」から以下コンポーネントをドラッグ&ドロップします。
- TButton × 1個
- TMemo × 1個
ソースコードの記述
以下のソースコードを記述します。
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
//素数の判定結果を入れるクラス
TAnswers=class(TObject)
public
res:TArray<String>;
end;
//並列プログラミング ライブラリの TTask を使用して
//Numが素数の場合はAnswers.res配列に追加する
TPrimeTest=class(TTask, ITask)
private
fNum:INT64;
fAnswers:TAnswers;
public
constructor Create(Num:Int64; Answers:TAnswers);
procedure TaskStart;
end;
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject); private
{ Private 宣言 }
Answers:TAnswers;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TPrimeTest }
constructor TPrimeTest.Create(Num: Int64; Answers: TAnswers);
begin
//プライベート変数に保存する
fNum:=Num;
fAnswers:=Answers;
//親クラスのCreateを呼び出す
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 は素数',[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; //素数ではない
break;
end;
inc(i);
end;
if flag then
st:=Format('%d は素数',[fNum]);
end;
if st<>'' then
begin
//同時にオブジェクト使用しないように保護(ロック)する
System.MonitorEnter(fAnswers);
try
//配列を1個増やす
SetLength(fAnswers.res,Length(fAnswers.res)+1);
fAnswers.res[Length(fAnswers.res)-1]:=st;
finally
//保護(ロック)を解除する
System.MonitorExit(fAnswers);
end;
end;
end;
{TForm1}
procedure TForm1.Button1Click(Sender: TObject);
var i,n:Int64;
Tasks:TArray<ITask>;
begin
Memo1.Lines.Clear;
SetLength(Answers.res,0);
//10個の並列処理用タスクを準備する
SetLength(Tasks,10);
//10000から50000 までの間の素数を見つける
n:=10000;
while n<50000 do
begin
Tasks[0]:=TPrimeTest.Create(n,Answers) as ITask;
inc(n);
Tasks[1]:=TPrimeTest.Create(n,Answers) as ITask;
inc(n);
Tasks[2]:=TPrimeTest.Create(n,Answers) as ITask;
inc(n);
Tasks[3]:=TPrimeTest.Create(n,Answers) as ITask;
inc(n);
Tasks[4]:=TPrimeTest.Create(n,Answers) as ITask;
inc(n);
Tasks[5]:=TPrimeTest.Create(n,Answers) as ITask;
inc(n);
Tasks[6]:=TPrimeTest.Create(n,Answers) as ITask;
inc(n);
Tasks[7]:=TPrimeTest.Create(n,Answers) as ITask;
inc(n);
Tasks[8]:=TPrimeTest.Create(n,Answers) as ITask;
inc(n);
Tasks[9]:=TPrimeTest.Create(n,Answers) as ITask;
inc(n);
//10個のタスクの並列処理を開始する
for i := Low(Tasks) to High(Tasks) do
Tasks[i].Start;
//全てのタスクが完了するまで待つ
//10個のタスクが開始する順序と終了する順序は保証されない
TTask.WaitForAll(Tasks);
end;
Memo1.Lines.BeginUpdate;
for i := Low(Answers.res) to High(Answers.res) do
Memo1.Lines.Add((Answers.res)[i]);
Memo1.Lines.EndUpdate;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
//回答用クラスのインスタンスを作成する
Answers:=TAnswers.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Answers.Free;
end;
end.
実行する
IDEの実行ボタンをクリックして実行します。
Button1をクリックすると、10000から50000までの間にある素数をMemo1に表示します。
