DelphiのTTaskでもContinueWithがしたい!


読んで字の如く。

前置き

DelphiのRTLは .NET Framework を後追いしている印象があり、
TTaskクラスを始めとした並列プログラミングライブラリも
割と最近のバージョン(XE7)で追加されました。
しかし基盤となる技術が異なる、設計思想が異なる等の理由で
メソッドや記述方法が違っていたり、そもそも機能がなかったりします。

継続処理は必要でしょ

並列処理を実装していくと、たいてい時間のかかる処理の前後で
UI操作を行ったり処理順を意識する場面が出てきたりします。
こういうとき .NET では ContinueWithメソッドを使用しますが、
残念ながらDelphiのTTaskクラスにはありません。

ということで作ってみました。
ダウンロード(MITライセンス)

TTaskクラスのヘルパーとして実装されているので
usesするだけで以下のように使用可能です。
メソッドチェーンももちろんOK。

Unit1.pas
//----------
uses
  System.Threading, WS.Threading;
//----------

procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1.Enabled := false;
  Label1.Text := '処理1...';

  // 時間のかかる処理(別スレッド)
  TTask.Run(procedure
    begin
      TThread.Sleep(5000);
      //raise EInvalidOperation.Create('例外テスト');
    end)
  // 継続処理のためUI更新(前スレッド完了時のみ。UIスレッド)
  .ContinueWith(procedure(t: ITask)
    begin
      Label1.Text := '処理2...';
    end, [TTaskContinuationOption.OnCompleted, TTaskContinuationOption.Synchronize])
  // 時間のかかる継続処理(前スレッド完了時のみ。別スレッド)
  .ContinueWith(procedure
    begin
      TThread.Sleep(5000);
    end, [TTaskContinuationOption.OnCompleted])
  // 後処理(UIスレッド)
  .ContinueWith(procedure
    begin
      Button1.Enabled := true;
      Label1.Text := '完了';
    end, [TTaskContinuationOption.Synchronize])
  ;
end;

ContinueWithに指定するプロシージャは前のタスクをパラメータに受け取ることもできます。
TTask.RunメソッドだけでなくTTask.Future<T>メソッドも継続可能になっていますが、
ContinueWith自体は戻り値を返せません。
本当はやりたかったけどインタフェースにジェネリックメソッドを定義できないので
断念しました…。

Delphi 10.1以降で動作確認しましたが
XE7以降なら動くかも。動いたら報告頂けると幸い。
またVCL、FMXのすべてのプラットホーム(Linux含む)で動作します。

ソースはMITライセンスに基づいて自由にしてもらって構いませんが、
バグ報告や機能追加のフィードバックもらえると喜びます。