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に表示します。