このページでは

Qt TaskTree C++ Classes

汎用 TaskTree ライブラリ。詳細...

このモジュールは開発中であり、変更される可能性があります。

このモジュールは Qt 6.11 で導入されました。

名前空間

QtTaskTree

TaskTree モジュールのすべてのクラスとグローバル関数を囲む

クラス

QtTaskTree::Do

For や When 構造体で使用されるボディ要素

QtTaskTree::Else

条件式で使用される "else" 要素

QtTaskTree::ElseIf

条件式で使われる "else if" 要素

QtTaskTree::ExecutableItem

実行可能なタスク項目の基本クラス

QtTaskTree::ExecutionMode

実行モードを記述するグループ要素

QtTaskTree::For

forループ要素

QtTaskTree::Forever

サブタスクの無限ループ

QtTaskTree::ForeverIterator

For要素の内部で使われる無限イテレータ

QtTaskTree::Group

非同期タスクのネストしたツリーをどのように実行し、処理するかを記述する宣言的レシピを構成するための基本要素を表します。

QtTaskTree::GroupItem

グループの一部となる基本要素を表します。

QtTaskTree::If

条件式で使用される "if "要素

QtTaskTree::Iterator

For要素の内部でイテレータとして使用される基本クラス

QtTaskTree::ListIterator

For要素の内部で使用されるリスト・イテレータ

QtTaskTree::ObjectSignal

QObjectサブクラスとそのシグナルを記述する構造体

QtTaskTree::ParallelLimit

カスタム制限による並列実行モード

QtTaskTree::QBarrier

オンデマンドで終了する非同期タスク

QtTaskTree::QCustomTask

カスタムタスクアイテムを宣言し、そのセットアップと完了ハンドラを定義するためのクラステンプレート

QtTaskTree::QDefaultTaskAdapter

QCustomTask で使われるデフォルトのタスク・アダプタを提供するクラス・テンプレート

QtTaskTree::QMappedTaskTreeRunner

指定された Key タイプでマップされたタスクツリー実行コントローラ

QtTaskTree::QNetworkReplyWrapper

QNetworkReply と QNetworkAccessManager のラッパー

QtTaskTree::QParallelTaskTreeRunner

並列タスク・ツリー実行コントローラ

QtTaskTree::QProcessTaskDeleter

QProcessTask で使用される QProcess 用のカスタムデレッ タ

QtTaskTree::QSequentialTaskTreeRunner

逐次タスクツリー実行コントローラ

QtTaskTree::QSingleTaskTreeRunner

単一タスクツリー実行コントローラ

QtTaskTree::QStartedBarrier

指定された制限で開始されたQBarrier

QtTaskTree::QSyncTask

他のタスクの間でカスタムハンドラを同期実行します。

QtTaskTree::QTaskInterface

カスタムタスクのインターフェイスを適合させるときに使われるヘルパークラス

QtTaskTree::QTaskTree

宣言的な方法で定義された非同期タスクのツリーを実行する

QtTaskTree::QTcpSocketWrapper

QTcpSocketのラッパー

QtTaskTree::QThreadFunction

QtConcurrent::run() による、別スレッドでの関数の実行を制御するクラステンプレートです。

QtTaskTree::QThreadFunctionBase

QThreadFunction クラステンプレートの基底クラス

QtTaskTree::RepeatIterator

For 要素の内部で使用する反復イテレータ

QtTaskTree::Storage

実行中のタスクツリーでのカスタムデータ交換のためのクラステンプレート

QtTaskTree::Then

条件式で使用される "then" 要素

QtTaskTree::UntilIterator

For 要素の内部で使用される条件イテレータ

QtTaskTree::When

バリアが進むまでボディの実行を遅延させる要素

詳細説明

TaskTree ライブラリを使用して、実行する非同期タスクを記述するレシピを構築し、QTaskTree 内でこれらのレシピを使用して実行します。

レシピは、どのようなタスク・タイプが作成され、実行されるかを宣言的に記述したものです:QProcess例えば、QNetworkReplyWrapperQThreadFunction<ReturnType>、順番に実行するか並列に実行するか、などです。レシピの中では、前のタスクが成功で終わったかエラーで終わったかによって、異なる継続パスを定義することができる。また、Group 要素の中にタスクを入れ子にすることも可能で、Group はそれぞれ独自の実行モードやワークフローポリシーに従ってタスクを実行することができる。レシピはタスクツリー構造を形成する。

非同期タスク

非同期タスクとは、タスクを開始し、成功またはエラーで終了するタスクのことです。後でとは、タスクを開始した後、実行中のイベント・ループに制御が戻ることを意味する。タスクが終了するまで、呼び出し元のスレッドをブロックすることはない。タスク・ツリーを使用するには、イベント・ループが回転する必要がある。

非同期タスクの例

レシピとタスクツリー

レシピとタスクツリーとは何かを覚えるために、カートリッジとプレーヤーに例えてみましょう。レシピを書くときは、カートリッジを作るようなもので、カートリッジがプレーヤー(タスクツリー)の中に置かれ、スタートしたときに、プレーヤーが後で何をすべきかの詳細な説明を準備するだけである。レシピそのものは、レシピがタスクツリーに渡され、タスクツリーが開始されたときに、タスクツリーが何をすべきかをタスクツリーに宣言的に記述したものにすぎない。レシピ自身はタスクツリーなしでは何もしません。プレーヤーなしのカートリッジのようなものです。

以下はレシピとタスクツリーの責任について簡単にまとめたものです。

レシピ(カートリッジ)は説明する:

  • (QCustomTaskを経由して)実行中のタスクツリーによって動的に作成されるタスクの内容
  • どの順番で
  • 実行中のタスクツリーによってどのようなデータ構造が動的に作成されるのか(Storage を通して)。
  • 開始前の各タスクのセットアップ方法
  • タスク終了時のデータ収集方法
  • 実行モード(タスクは順番に実行するか並列に実行するか)
  • ワークフローポリシー

タスクツリー(プレイヤー):

  • レシピを読み込み、タスクとデータ構造を自動的に作成する
  • 作成されたタスクとデータ構造のライフタイム管理
  • 継続を実行
  • 終了したタスクの結果とワークフローポリシーによって異なるパスを選択する
  • 基本的な進捗情報を提供

カスタムタスク

レシピはタスクツリーが開始されたときにどのようなタスクを作成すべきかをタスクツリーに説明するものなので、レシピの中で直接これらのタスクを作成することはできない。その代わりに、タスクツリーにこれらのタスクを作成し、後で開始するように指示する宣言的な方法が必要です。例えば、タスクツリーにQProcess を作成、開始させたい場合、QProcessTask 要素をレシピの中に記述します。QProcessTaskQCustomTask<QProcess> のエイリアスである。各タスクタイプは対応するQCustomTask<Type>を提供し、レシピの中で使用できるようにする。

以下の表はレシピの中に配置できるカスタムタスクの例です:

カスタムタスク(レシピで使用)タスククラス(実行中のタスクツリーによって作成される)簡単な説明
QProcessTaskQProcessプロセスを開始する。
QThreadFunctionTask<ReturnTypeQThreadFunction<ReturnType>別スレッドで実行される非同期タスクを開始する。
QTaskTreeTaskQTaskTreeネストされたタスクツリーを開始する。
QNetworkReplyWrapperTaskQNetworkReplyWrapperネットワークダウンロード開始
QTcpSocketWrapperTaskQTcpSocketWrapperTCP接続の開始

レシピの中で使われる特定のタスクの適応方法についての詳細はQTaskInterfaceTask Adapters を参照のこと。

レシピ例

QTaskTree にはトップレベルのGroup 要素、別名レシピがあり、QProcessTaskQNetworkReplyWrapperTaskQThreadFunctionTask<ReturnType> のような様々なタイプのタスクをいくつでも含むことができます:

const Group recipe {
    QProcessTask(...),
    QNetworkReplyWrapperTask(...),
    QThreadFunctionTask<int>(...)
};

QTaskTree *taskTree = new QTaskTree(recipe);
connect(taskTree, &QTaskTree::done, ...);  // finish handler
taskTree->start();

上記のレシピはQProcessTaskQNetworkReplyWrapperTaskQThreadFunctionTask<int> タイプのタスクを含むGroup タイプのトップレベルエレメントで構成されます。taskTree->start() が呼ばれた後、タスクが作成され、QProcess から始まるチェーンで実行される。QProcess が正常に終了すると、QNetworkReplyWrapper タスクが開始される。最後に、ネットワーク・タスクが正常に終了すると、QThreadFunction<int> タスクが開始される。

最後に実行されたタスクが成功裏に終了すると、タスク・ツリーは正常に実行されたとみなされ、DoneWith::SuccessQTaskTree::done() シグナルが発せられる。タスクがエラーで終了すると、タスク・ツリーの実行は停止され、残りのタスクはスキップされる。タスク・ツリーはエラーで終了し、DoneWith::Error とともにQTaskTree::done() シグナルを送出する。

グループ

Group の親は、これを1つのタスクと見なす。他のタスクと同様に、グループも開始することができ、成功またはエラーで終了することができる。Group 要素を入れ子にしてツリー構造を作ることができる:

const Group recipe {
    Group {
        parallel,
        QProcessTask(...),
        QThreadFunctionTask<int>(...)
    },
    QNetworkReplyWrapperTask(...)
};

上の例は最初の例と異なり、トップレベル要素にQProcessTaskQThreadFunctionTask<int> を含むサブグループがある。サブグループはルートのQNetworkReplyWrapperTask の兄弟要素です。サブグループには、そのGroup にタスクを並行して実行するよう指示する追加のparallel 要素が含まれます。

したがって、QTaskTree が上記のレシピを開始すると、QProcessQThreadFunction<int> が直ちに開始され、並行して実行される。ルートグループにはparallel 要素がないので、その直接の子タスクは順番に実行される。したがって、QNetworkReplyWrapper はサブグループ全体が終了したときに開始する。グループは、すべてのタスクが終了した時点で終了したとみなされる。タスクの終了順序は関係ない。

したがって、どちらのタスクが長く続くか(QProcess またはQThreadFunction<int>)によって、次のようなシナリオが起こりうる:

シナリオ1シナリオ2
ルートグループ開始ルートグループ開始
サブグループ開始サブグループ開始
QProcess 開始QProcess 開始
QThreadFunction<int>スタートQThreadFunction<int>スタート
......
QProcess 終了QThreadFunction<int> finishes
......
QThreadFunction<int> finishesQProcess フィニッシュ
サブグループの終了サブ・グループ終了
QNetworkReplyWrapper開始QNetworkReplyWrapperスタート
......
QNetworkReplyWrapper終了QNetworkReplyWrapper終了
ルート・グループ終了ルート・グループ終了

シナリオ間の違いは太字で示されています。つのドットは、前のイベントと次のイベントの間に不特定の時間が経過していることを意味します(タスクが実行され続ける)。イベント間に点がない場合は、それらが同期して発生することを意味する。

提示されたシナリオは、全てのタスクが正常に実行されることを前提としている。タスクが実行中に失敗した場合、タスクツリーはエラーで終了する。特に、QThreadFunction<int> がまだ実行されている間にQProcess がエラーで終了すると、QThreadFunction<int> は自動的にキャンセルされ、サブグループはエラーで終了し、QNetworkReplyWrapper はスキップされ、ツリーはエラーで終了する。

タスクハンドラ

Task ハンドラを使用して、タスクの実行をセットアップし、タスクが成功またはエラーで終了したときに、タスクからの出力データを読み出せるようにする。

タスク開始ハンドラ

タスクオブジェクトが生成され、それが開始される前に、タスクツリーはオプションでユーザーが提供するセットアップハンドラを呼び出します。セットアップハンドラは常に関連するタスククラスオブジェクトへの参照を取る必要があります:

const auto onSetup = [](QProcess &process) {
    process.setProgram("sleep");
    process.setArguments({"3"});
};
const Group root {
    QProcessTask(onSetup)
};

渡されたQProcess をセットアップハンドラ内で変更することで、タスクツリーはあなたの設定に従って処理を開始することができる。タスクツリーは必要に応じてprocess.start(); を呼び出すので、セットアップハンドラの中で を呼び出すべきではありません。セットアップハンドラはオプションである。使用する場合は、タスクのコンストラクタの最初の引数でなければならない。

オプションとして、セットアップハンドラはSetupResult を返すことができる。 返されたSetupResult は、与えられたタスクのそれ以降の開始動作に影響を与える。返される値は次のとおりである:

SetupResult簡単な説明
Continueタスクは普通に開始される。これはセットアップハンドラがSetupResult を返さないときのデフォルトの動作である (つまり、その戻り値の型がvoid である)。
StopWithSuccessタスクは開始されず、親に成功を報告する。
StopWithErrorタスクは開始されず、親にエラーを報告する。

これは、ある条件が満たされたときにのみタスクを実行し、その条件を評価するために必要なデータは、先に開始されたタスクが終了するまでわからないという場合に便利です。このようにして、セットアップ・ハンドラは、対応するタスクを通常通り開始するか、スキップして成功またはエラーを報告するかを動的に決定する。タスク間データ交換の詳細については、Storage を参照のこと。

タスクの完了ハンドラ

実行中のタスクが終了すると、タスクツリーはオプションで提供されるdoneハンドラを呼び出します。ハンドラは関連するタスククラスオブジェクトへのconst 参照を取る必要があります:

const autoonSetup= [](QProcessプロセス) { process.setProgram("sleep"); process.setArguments({"3"}); };const autoonDone= [](constQProcess&process,DoneWith result) {if(result==DoneWith::Success)        qDebug() << "Success" << process.cleanedStdOut();
   その他        qDebug() << "Failure" << process.cleanedStdErr();
};constGroup root {QProcessTask(onSetup,onDone) };

done ハンドラーは、QProcess から出力データを収集し、さらなる処理のために保存したり、追加のアクションを実行したりすることができます。

注: タスク・セットアップ・ハンドラがStopWithSuccess またはStopWithError を返した場合、done ハンドラは呼び出されません。

グループハンドラ

タスクハンドラと同様に、グループハンドラを使うと、実行するグループを設定し、グループ全体が成功またはエラーで終了したときに、さらにアクションを適用することができます。

グループ開始ハンドラ

タスクツリーは子タスクを開始する前にグループ開始ハンドラを呼び出します。グループハンドラは引数をとりません:

const autoonSetup= []{ グループハンドラは引数を取りません。    qDebug() << "Entering the group";
};constGroup root { onGroupSetup(onSetup), QProcessTask(...) };

グループ・セットアップ・ハンドラはオプションです。グループ・セットアップ・ハンドラを定義するには、onGroupSetup ()要素をグループに追加します。onGroupSetup() の引数はユーザー・ハンドラです。1つのグループに複数のonGroupSetup() 要素を追加すると、実行時にエラー・メッセージを含むアサートが発生します。

タスクの開始ハンドラと同様に、グループ開始ハンドラもSetupResult を返すことがある。返されたSetupResult 値は、グループ全体の開始動作に影響します。グループ開始ハンドラを指定しない場合、またはその戻り値の型が void の場合、デフォルトのグループの動作はContinue となり、すべてのタスクが正常に開始されます。それ以外の場合、開始ハンドラがStopWithSuccess またはStopWithError を返すと、タスクは開始されず(スキップされ)、グループ自体がそれぞれ返された値に応じて成功またはエラーを報告します。

const Group root {
    onGroupSetup([] { qDebug() << "Root setup"; }),
    Group {
        onGroupSetup([] { qDebug() << "Group 1 setup"; return SetupResult::Continue; }),
        QProcessTask(...) // Process 1
    },
    Group {
        onGroupSetup([] { qDebug() << "Group 2 setup"; return SetupResult::StopWithSuccess; }),
        QProcessTask(...) // Process 2
    },
    Group {
        onGroupSetup([] { qDebug() << "Group 3 setup"; return SetupResult::StopWithError; }),
        QProcessTask(...) // Process 3
    },
    QProcessTask(...) // Process 4
};

上記の例では、ルートグループのすべてのサブグループがセットアップハンドラを定義している。以下のシナリオでは、開始されたすべてのプロセスが成功裏に終了することを想定しています:

シナリオコメント
ルートグループの開始SetupResultを返さないため、タスクが実行される。
グループ1開始Continueを返すので、タスクが実行される。
プロセス1開始
......
プロセス1終了(成功)
グループ1終了(成功)
グループ2開始StopWithSuccess を返すため、プロセス 2 はスキップされ、グループ 2 は成功を報告する。
グループ 2 終了(成功)
グループ 3 開始StopWithError を返すため、プロセス 3 はスキップされ、グループ 3 はエラーを報告する。
グループ 3 が終了する(エラー)
ルートグループ終了(エラー)ルートグループの直接の子であるグループ 3 がエラーで終了したため、ルートグループは実行を停止し、まだ開始していないプロセス 4 をスキップしてエラーを報告します。

グループの完了ハンドラ

Group の done ハンドラーは、タスクの実行が成功または失敗した後に実行される。グループによって報告される最終値は、Workflow Policy に依存する。ハンドラは、他の必要なアクションを適用することができる。done ハンドラは、グループのonGroupDone() 要素内で定義される。オプションの引数DoneWith を取ることができ、実行の成功または失敗を示す:

constGroup root { onGroupSetup([]{qDebug()<< "Root setup"; }), QProcessTask(...),onGroupDone([](DoneWith result) {if(result==DoneWith::Success)            qDebug() << "Root finished with success";
       その他            qDebug() << "Root finished with an error";
    }) };

グループdoneハンドラはオプションである。1つのグループに複数のonGroupDone() を追加すると、実行時にエラーメッセージを含むアサートが発生します。

注意: グループ設定ハンドラがStopWithSuccess またはStopWithError を返しても、グループの done ハンドラは起動される。この動作はタスク done ハンドラの動作とは異なり、将来変更される可能性があります。

その他のグループ要素

グループには、execution modeworkflow policy のような、処理フローを記述する他の要素を含めることができる。また、グループの実行中に収集されたカスタム共通データの収集と共有を担当するストレージ要素を含めることもできる。

実行モード

グループの実行モード要素は、グループの直接の子タスクの開始方法を指定する。最も一般的な実行モードはsequentialparallel です。ParallelLimit 要素を使用することで、並列実行するタスクの上限を指定することも可能です。

どの実行モードでも、グループは出現した順にタスクを開始します。

グループの子もグループである場合、子グループは自身の実行モードに従ってタスクを実行する。

ワークフローポリシー

Group のワークフロー ポリシー エレメントは、直接の子タスクが終了したときのグループの動作を指定します。可能なポリシーの詳細については、WorkflowPolicy を参照してください。

グループの子もグループである場合、子グループは自身のワークフロー ポリシーに従ってタスクを実行します。

ストレージ

タスク間の情報交換には、Storage 要素を使用します。特に逐次実行モードでは、あるタスクが開始する前に、既に終了している別のタスクからデータを必要とする場合。例えば、ソースからデータを読み出し、デスティネーションに書き込むことでデータをコピーするタスクツリーは以下のようになる:

staticQByteArrayload(constQString&fileName) {...}static voidsave(constQString&fileName, constQByteArray&array) {...}staticGroup copyRecipe(constQStringコピー元, constQStringstructCopyStorage {// [1] カスタムタスク間構造体       QByteArraycontent;// [2] カスタムタスク間データ};// [3] タスクツリーで管理可能なカスタムタスク間構造体のインスタンス const  Storage<CopyStorage>storage;const autoonLoaderSetup= [source](QThreadFunction<QByteArray> &async) { async.setThreadFunctionData(&load,source); };// [4] ランタイム: タスクツリーはハンドラを起動する前に [7] からインスタンスをアクティブにする const autoonLoaderDone= [storage](const  QThreadFunction<QByteArray> &async) { storage->content =async.result();// [5] ローダは結果をストレージに格納する};// [4] ランタイム: ハンドラを起動する前にタスクツリーは [7] からインスタンスをアクティブにする const autoonSaverSetup= [storage,destination](QThreadFunction<void> &async) {constQByteArraycontent=  storage->content;// [6] セーバーはストレージからデータを取得async.setThreadFunctionData(&save,destination,content); };const autoonSaverDone= [](const  QThreadFunction<void> &async) { { constautoonSaverDone= [](const QThreadFunction<void> &async)        qDebug() << "Save done successfully";
    };constGroup root {// [7]ランタイム: rootが入力されると、タスクツリーはCopyStorageのインスタンスを作成するstorage, QThreadFunctionTask<QByteArray>(onLoaderSetup,onLoaderDone,CallDoneFlag::OnSuccess),QThreadFunctionTask<void>(onSaverSetup,onSaverDone,CallDoneFlag::OnSuccess) };returnroot; }...constQStringsource= ...;constQStringdestination= ...;QTaskTreetaskTree(copyRecipe(source,destination)); connect(&taskTree, &QTaskTree::done, &taskTree, [](DoneWith result) {if(result==DoneWith::Success)        qDebug() << "The copying finished successfully.";
}); tasktree.start();

上記の例では、タスク間データは、CopyStorage カスタム構造体 [1]で囲まれたQByteArray コンテンツ変数 [2]で構成されている。ローダーが正常に終了すると、CopyStorage::content 変数 [5] にデータが格納される。その後、セーバーはこの変数を使用して保存タスクを構成する [6]。

タスクツリーでCopyStorage 構造体を管理できるように、Storage<CopyStorage> のインスタンスが作成される [3]。このオブジェクトのコピーがグループの子アイテムとして挿入されている場合 [7]、タスクツリーがこのグループに入ると、CopyStorage 構造体のインスタンスが動的に作成される。タスクツリーがこのグループから離れると、CopyStorage 構造体の既存のインスタンスは不要になるため破棄される。

共通のStorage<CopyStorage> インスタンスのコピーを保持する複数のタスク・ツリーが同時に実行される場合(タスク・ツリーが異なるスレッドで実行される場合を含む)、各タスク・ツリーには独自のCopyStorage 構造体のコピーが含まれる。

グループ内のどのハンドラーからでも、ストレージ・オブジェクトを使ってCopyStorage にアクセスできる。これには、ストレージ・オブジェクトを持つグループのすべての子孫タスクのすべてのハンドラが含まれます。ハンドラでカスタム構造体にアクセスするには、Storage<CopyStorage> オブジェクトのコピーをハンドラに渡します(ラムダ・キャプチャなど) [4]。

タスクツリーがストレージを含むサブツリー内のハンドラーを呼び出すと [7]、タスクツリーはStorage<CopyStorage> オブジェクト内の自身のCopyStorage インスタンスをアクティブにする。したがって、CopyStorage 構造体には、ハンドラ本体からのみアクセスできる。Storage<CopyStorage> 内から現在アクティブなCopyStorage にアクセスするには、Storage::operator->(),Storage::operator*(),Storage::activeStorage() メソッドを使用する。

以下のリストは、Storageオブジェクトをタスクツリーに採用する方法をまとめたものである:

  1. カスタムデータ[1]、[2]でカスタム構造体MyStorage を定義する。
  2. Storage<MyStorage> ストレージのインスタンスを作成する [3] 。
  3. Storage<MyStorage> インスタンスをハンドラーに渡す [4] 。
  4. ハンドラーでMyStorage インスタンスにアクセスする [5], [6]
  5. Storage<MyStorage> インスタンスをグループに挿入する [7] 。

QTaskTreeクラス

QTaskTree は、Group ルート要素によって記述されたレシピに従って、非同期タスクのツリー構造を実行します。

QTaskTree も非同期タスクなので、別のQTaskTree の一部になることができます。ネストされたQTaskTree を別のQTaskTree の中に配置するには、QTaskTreeTask 要素を別のGroup 要素に挿入します。

QTaskTree は、実行中に完了したタスクの進行状況を報告します。タスクが終了したり、スキップされたり、キャンセルされたりすると、進捗値が増加します。QTaskTree が終了してQTaskTree::done() シグナルが発せられると、進捗の現在値は進捗の最大値と等しくなる。進捗の最大値は、ツリー内の非同期タスクの総数に等しい。ネストされたQTaskTree は1つのタスクとしてカウントされ、その子タスクはトップ・レベル・ツリーではカウントされない。グループ自体はタスクとしてカウントされないが、そのタスクはカウントされる。QSyncTask タスクは非同期ではないので、タスクとしてカウントされない。

実行中のツリーに追加の初期データを設定するには、ストレージ設定ハンドラをインストールして、ツリーの作成時にツリーのストレージ・インスタンスを変更します:

Storage<CopyStorage> storage;
const Group root = ...; // storage placed inside root's group and inside handlers
QTaskTree taskTree(root);
auto initStorage = [](CopyStorage &storage) {
    storage.content = "initial content";
};
taskTree.onStorageSetup(storage, initStorage);
taskTree.start();

実行中のタスクツリーがCopyStorage インスタンスを作成するとき、ツリー内のハンドラーが呼び出される前に、タスクツリーはinitStorage ハンドラーを呼び出す。これは、この特定の実行taskTree に固有のストレージの初期データを設定できるようにするためである。

同様に、実行中のツリーから追加の結果データを収集するには、ツリー内のスト レージインスタンスが破棄されそうになったときに、そこからデータを読み取る。これを行うには、ストレージdoneハンドラをインストールする:

Storage<CopyStorage>storage;constGroup root= ...;// ルートのグループ内およびハンドラ内に配置されたストレージQTaskTreetaskTree(root);autocollectStorage= [](constCopyStorage&storage) { { { { {    qDebug() << "final content" << storage.content;
}; taskTree.onStorageDone(storage,collectStorage); taskTree.start();

taskTree実行中のタスクツリーがCopyStorage インスタンスを破棄しようとするとき、タスクツリーは collectStorage ハンドラーを呼び出す。

タスクアダプター

新しいタスクタイプをレシピの一部にすることは非常に簡単である。QCustomTask テンプレートに新しいタスクエイリアスを定義し、Task タイプをテンプレートの最初の引数として渡せばよい:

class Worker : public QObject
{
public:
    void start() { ... }

signals:
    void done(bool result);
};

using WorkerTask = QCustomTask<Worker>;

以下の条件を満たせば、これは機能する:

  1. タスクがQObject から派生している。
  2. タスクがpublic start()メソッドを持っている。
  3. タスクが終了すると、done(bool) または done(DoneResult) シグナルを発する。

タスクがこれらの条件を満たしていない場合でも、カスタム・アダプタで 2 番目のテンプレート引数を指定することで、タスクを TaskTree フレームワークで動作するように調整できます。例えば、QTimer を TaskTree で動作するように適応させたいとします。Adapter は次のようになります:

class TimerAdapter
{
public:
    void operator()(QTimer *task, QTaskInterface *iface) {
        task->setSingleShot(true);
        QObject::connect(task, &QTimer::timeout, iface, [iface] {
            iface->reportDone(DoneResult::Success);
        });
        task->start();
    }
};

using TimerTask = QCustomTask<QTimer, TimerAdapter>;

これで、TimerTask をレシピで使い始めることができます:

const autoonSetup= [](QTimertask.setInterval(2000); };const autoonDone= [](constQTimerタスク) { }; const auto onDone = [](const    qDebug() << "Timer triggered after" << task.interval() << "ms.";
};constGroup recipe { TimerTask(onSetup,onDone) };

注: 実行タスクを実装するクラスはデフォルトのコンストラクタを持ち、このクラスのオブジェクトは自由に破壊可能であるべきです。できれば、実行中のタスクの終了を待たずに、実行中のタスクを破壊できるようにすべきである(つまり、実行中のタスクの安全なノンブロッキング・デストラクタ)。ブロッキングデストラクタを持つタスクのノンブロッキング破壊を実現するには、QCustomTask のオプションのDeleter テンプレートパラメータ(3番目のテンプレート引数)の使用を検討する。

タスク・ツリー・ランナー

タスクツリーランナーは与えられたレシピを実行するために使われる基礎となるQTaskTree の寿命を管理します。

以下の表は様々なタスクツリーランナーの違いをまとめたものです:

クラス名クラス名
QSingleTaskTreeRunner単一のタスクツリーの実行を管理します。QSingleTaskTreeRunner::start() メソッドは渡されたレシピを無条件に開始し、実行中のタスクツリーをリセットします。一度に実行できるタスクツリーは1つだけです。
QSequentialTaskTreeRunner連続したタスクツリーの実行を管理します。QSequentialTaskTreeRunner::enqueue() メソッドは、タスクツリーランナーがアイドルの場合、渡されたレシピを開始します。そうでない場合、レシピはキューに入れられます。現在のタスクが終了すると、ランナーはデキューされたレシピを順次実行します。一度に実行できるタスクツリーは1つだけです。
QParallelTaskTreeRunnerタスクツリーの並列実行を管理します。QParallelTaskTreeRunner::start() メソッドは無条件に渡されたレシピを開始し、実行中のタスクツリーを並列に保ちます。
QMappedTaskTreeRunnerマップされたタスクツリーの実行を管理します。QMappedTaskTreeRunner::start() メソッドは無条件に指定されたキーの指定されたレシピを開始します。すでに同じキーで別のタスクツリーが実行されている場合、それはリセットされます。異なるキーを持つタスクツリーは影響を受けず、実行を継続します。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.