このページでは

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 、QNetworkReplyWrapper 、またはQThreadFunction<ReturnType>)、あるいはそれらを順次実行するか並列実行するかを記述した宣言的な記述です。 レシピ内では、前のタスクが正常に完了したかエラーで終了したかによって、異なる継続パスを定義することができます。また、Group 要素内にタスクをネストすることも可能であり、各Group は、独自の実行モードやワークフローポリシーに従ってタスクを実行することができます。これらのレシピが、タスクのツリー構造を形成します。

非同期タスク

非同期タスクとは、開始された後、成功またはエラーで終了するあらゆるタスクを指します。「後」とは、タスクの開始後、制御が実行中のイベントループに戻ることを意味します。タスクが完了するまで、呼び出し元のスレッドをブロックすることはありません。タスクツリーを使用するには、イベントループが稼働している必要があります。

非同期タスクの例:

レシピとタスクツリー

レシピとタスクツリーが何であるかを理解するために、カートリッジとプレーヤーに例えてみましょう。レシピを書くことは、カートリッジを組み立てるようなものです。つまり、カートリッジがプレーヤー(タスクツリー)に挿入され、起動された際に、プレーヤーが何をすべきかについて詳細な説明を用意するだけです。 レシピ自体は、レシピがタスクツリーに渡され、タスクツリーが起動された際に、タスクツリーが何をすべきかを記述した宣言的な説明に過ぎません。レシピ自体は、タスクツリーなしでは単独で何も行いません。それは、プレーヤーのないカートリッジのようなものです。

以下に、レシピとタスクツリーの役割について簡単にまとめます。

レシピ(カートリッジ)は以下を記述します:

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

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

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

カスタムタスク

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

以下の表は、レシピ内に配置できる組み込みのカスタムタスクの一部を示しています:

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

特定のタスクをレシピ内で使用できるように適応させる方法の詳細については、QTaskInterface およびTask Adapters を参照してください。

レシピの例

QTaskTree には、最上位のGroup 要素(通称「レシピ」)があり、これにはQProcessTask 、QNetworkReplyWrapperTask 、QThreadFunctionTask<ReturnType> など、さまざまなタイプのタスクをいくつでも含めることができます:

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

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

上記のレシピは、Group 型の最上位要素で構成されており、その中にQProcessTask 型、QNetworkReplyWrapperTask 型、およびQThreadFunctionTask<int>型のタスクが含まれています。taskTree->start() が呼び出されると、QProcess から順に、タスクが生成され、チェーン状に実行されます。QProcess が正常に完了すると、QNetworkReplyWrapper タスクが開始されます。最後に、ネットワークタスクが正常に完了すると、QThreadFunction<int>タスクが開始されます。

最後の実行中のタスクが正常に終了すると、タスクツリーは正常に実行されたものとみなされ、DoneWith::Success を含むQTaskTree::done() シグナルが発信されます。タスクがエラーで終了した場合、タスクツリーの実行は停止され、残りのタスクはスキップされます。タスクツリーはエラーで終了し、DoneWith::Error を含むQTaskTree::done() シグナルを送信します。

グループ

Group の親は、これを単一のタスクとして認識します。他のタスクと同様に、グループも起動可能であり、正常またはエラーで終了することがあります。Group 要素をネストさせて、ツリー構造を作成することができます:

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

上記の例は、最初の例とは異なり、最上位要素に、QProcessTask およびQThreadFunctionTask<int>を含むサブグループがあります。このサブグループは、ルートにあるQNetworkReplyWrapperTask と同等の要素です。サブグループには、追加のparallel 要素が含まれており、これによりGroup に対してタスクを並列で実行するよう指示しています。

したがって、QTaskTree が上記のリシピを開始すると、QProcess とQThreadFunction<int>が直ちに開始され、並列で実行されます。ルートグループにはparallel 要素が含まれていないため、その直接の子タスクは順次実行されます。したがって、QNetworkReplyWrapper はサブグループ全体が完了した時点で開始されます。グループは、そのすべてのタスクが完了した時点で完了したとみなされます。タスクが完了する順序は関係ありません。

したがって、どのタスクがより長くかかるか(QProcess またはQThreadFunction<int>)によって、次のようなシナリオが発生する可能性があります:

シナリオ 1シナリオ 2
ルートグループが開始されるルートグループが開始
サブグループの開始サブグループが開始
QProcess 開始QProcess 開始
QThreadFunction<int> を開始QThreadFunction<int> 開始
......
QProcess 終了QThreadFunction<int> が終了する
......
QThreadFunction<int> finishesQProcess finishes
サブグループが終了サブグループが終了
QNetworkReplyWrapper が開始されますQNetworkReplyWrapper が開始されます
......
QNetworkReplyWrapper が終了しましたQNetworkReplyWrapperが終了しました
ルートグループが終了しましたRoot Group が完了しました

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

提示されたシナリオは、すべてのタスクが正常に実行されることを前提としています。実行中にタスクが失敗した場合、タスクツリーはエラーで終了します。特に、`QProcess ` がエラーで終了し、`QThreadFunction<int>` がまだ実行中の場合、`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ハンドラ

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

const autoonSetup= [](QProcess&process) {
    process.setProgram("sleep");
    process.setArguments({"3"});
};
const autoonDone= [](constQProcess&process,DoneWith result) {
    if(result==DoneWith::Success)
        qDebug() << "Success" << process.cleanedStdOut();
   else
        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をスキップして、エラーを報告します。

グループのDoneハンドラ

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";
       else
            qDebug() << "Root finished with an error";
    })
};

グループの完了ハンドラーはオプションです。1つのグループに複数の `onGroupDone()` を追加すると、実行時にエラーメッセージを含むアサートがトリガーされます。

注: グループのセットアップハンドラが `StopWithSuccess ` または `StopWithError`を返した場合でも 、グループの完了ハンドラは呼び出されます。この動作はタスクの完了ハンドラの動作とは異なり、将来変更される可能性があります。

その他のグループ要素

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

実行モード

グループ内の execution mode 要素は、そのグループの直接の子タスクがどのように開始されるかを指定します。最も一般的な実行モードは、sequential およびparallel です。また、ParallelLimit 要素を使用することで、並行して実行されるタスクの上限を指定することも可能です。

どの実行モードにおいても、グループはタスクが記述されている順序でタスクを開始します。

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

ワークフローポリシー

Group 内のワークフローポリシー要素は、グループの直接の子タスクのいずれかが完了した際に、そのグループがどのように振る舞うべきかを指定します。適用可能なポリシーの詳細については、WorkflowPolicy を参照してください。

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

ストレージ

タスク間で情報をやり取りするには、Storage 要素を使用します。特に、順次実行モードにおいて、あるタスクが開始する前に、すでに完了している別のタスクからのデータを必要とする場合などに使用します。たとえば、ソースからデータを読み取り、宛先に書き込むことでデータをコピーするタスクツリーは、次のような構成になります:

staticQByteArray load(constQString&fileName) {...}
static voidsave(constQString&fileName, constQByteArray&array) {...}

staticGroup copyRecipe(constQString&source, constQString&destination)
{
    structCopyStorage {// [1] タスク間用のカスタム構造体
        QByteArray content;// [2] カスタムタスク間データ
    };

    // [3] タスクツリーで管理可能なカスタムタスク間構造体のインスタンス
    constStorage<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) {
        constQByteArray content= storage->content;// [6] セーバーはストレージからデータを取得する
        async.setThreadFunctionData(&save,destination,content);
    };
    const autoonSaverDone= [](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;
}

...

constQString source=...;
constQString destination=...;
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. カスタムデータを含むカスタム構造体 `MyStorage ` を定義します [1], [2]
  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 は単一のタスクとしてカウントされ、その子タスクは最上位ツリーではカウントされません。グループ自体はタスクとしてカウントされませんが、その中のタスクはカウントされます。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 のこの特定の実行に固有のストレージの初期データを設定できるようにします。

同様に、実行中のツリーから追加の結果データを収集するには、ツリー内のストレージインスタンスが破棄されようとしている際に、そこからデータを読み取ります。これを行うには、ストレージの完了ハンドラを登録します:

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

実行中のタスクツリーがCopyStorage インスタンスを破棄しようとする際、タスクツリーはcollectStorageハンドラを呼び出し、taskTree のこの特定の実行に固有の最終データをストレージから読み取れるようにします。

タスクアダプタ

新しいタスク型をレシピに組み込むのは非常に簡単です。QCustomTask テンプレートに対して新しいタスクエイリアスを定義し、最初のテンプレート引数としてTask 型を渡すだけで十分です。例えば、次のようにします:

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

signals:
    void done(bool result);
};

using WorkerTask = QCustomTask<Worker>;

以下の条件が満たされていれば、これは正常に動作します:

  1. タスクが `QObject` から派生していること。
  2. タスクには、タスクを開始するパブリックな 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= [](QTimer&task) {
    task.setInterval(2000);
};

const autoonDone= [](constQTimer&task) {
    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.