並列プログラミング ライブラリの TTask の使用

提供: RAD Studio
移動先: 案内検索

並列プログラミング ライブラリの使用 への移動


並列プログラミング ライブラリ(PPL)には、1 つまたは複数のタスクを並列に実行するための TTask クラスが用意されています。タスクは、完了すべき作業の単位です。PPL では、タスクとそのタスクを実行するスレッドの関連付けを行うので、独自のカスタム スレッドを作成し管理しなくても、複数のタスクを並列に実行することができます。

TTask では、ITask のインスタンスとのやり取りを作成し管理します。ITask は、広範囲な StartWaitCancel へのメソッドやプロパティ、また Status のプロパティ(Created、WaitingToRun、Running、Completed、WaitingForChildren、Canceled、Exception)を提供するインターフェイスです。

バックグラウンドでのタスクの実行

TTask の 1 つの機能は、何らかの処理をバックグラウンドで開始する場合にユーザー インターフェイスが動かなくなるのを避けることです。 次のコード例では、単一のタスクを作成し開始する方法を示しています:

Delphi:

 
procedure TForm1.Button1Click(Sender: TObject);
var
 aTask: ITask;
begin
 aTask := TTask.Create(
   procedure
   begin
     sleep (3000); // 3 seconds
     TThread.Synchronize(TThread.Current,
       procedure
       begin
         ShowMessage ('Hello');
       end);
   end);
   aTask.Start;
end;

C++:

Clang 拡張 C++ コンパイラを使用している場合、ラムダ式を使用することができます:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    _di_ITask task = TTask::Create([&](){
        Sleep(3000);
        ShowMessage("Hello");
    });
    task->Start();
}

C++ コンパイラの場合、TProc サブクラスを宣言し、そのインスタンスを _di_TProc としてキャストして使用します:

class TCppTask : public TCppInterfacedObject<TProc> {
public:
    void __fastcall Invoke() {
        Sleep(3000);
        ShowMessage("Hello");
    }
};

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    _di_ITask task = TTask::Create(_di_TProc(new TCppTask()));
    task->Start();
}

タスクが完了するのを待機する

TTask には、すべてまたは任意のタスクが完了するのを待つための、WaitForAllWaitForAny が用意されています。WaitForAll が、すべてのタスクの完了時に制御を返すのに対して、WaitForAny は最初に完了したタスクを通知します。たとえば、2 つのタスク A と B があり、それぞれ 3 秒と 5 秒かかる場合、結果が得られるまでの時間は次のとおりです:

次の例では、WaitForAll メソッドを使用しています:

Delphi:

 
procedure TForm1.MyButtonClick(Sender: TObject);
var 
  tasks: array of ITask; 
  value: Integer; 
begin 
  Setlength (tasks ,2); 
  value := 0; 

 tasks[0] := TTask.Create (procedure () 
  begin 
   sleep(3000);
   TInterlocked.Add (value, 3000); 
  end); 
 tasks[0].Start; 

 tasks[1] := TTask.Create (procedure () 
   begin 
   sleep (5000);
   TInterlocked.Add (value, 5000);
 end); 
 tasks[1].Start; 
 
 TTask.WaitForAll(tasks); 
 ShowMessage ('All done: ' + value.ToString); 
end;

C++:

Clang 拡張 C++ コンパイラを使用している場合、ラムダ式を使用することができます:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    _di_ITask tasks[2];
    int value = 0;

    tasks[0] = TTask::Create([&](){
        Sleep(3000);
        TInterlocked::Add(value, 3000);
    });
    tasks[0]->Start();

    tasks[1] = TTask::Create([&](){
        Sleep(5000);
        TInterlocked::Add(value, 5000);
    });
    tasks[1]->Start();

    TTask::WaitForAll(tasks, sizeof(tasks)/sizeof(tasks[0])-1);
    ShowMessage("All done! " + IntToStr(value));
}

C++ コンパイラの場合、TProc サブクラスを宣言し、そのインスタンスを _di_TProc としてキャストして使用します:

class TCppTask : public TCppInterfacedObject<TProc> {
public:
    TCppTask(int &value, int increase) : m_value(value), m_increase(increase) {}
    void __fastcall Invoke() {
        Sleep(m_increase);
        TInterlocked::Add(m_value, m_increase);
    }
protected:
    int& m_value;
    int m_increase;
};

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    _di_ITask tasks[2];
    int value = 0;

    tasks[0] = TTask::Create(_di_TProc(new TCppTask(value, 3000)));
    tasks[0]->Start();

    tasks[1] = TTask::Create(_di_TProc(new TCppTask(value, 5000)));
    tasks[1]->Start();

    TTask::WaitForAll(tasks,(sizeof(tasks)/sizeof(tasks[0])-1));
    ShowMessage("All done! " + IntToStr(value));
}

関連項目