キャンセルと入れ子の並列処理

これまでは、並列処理が入れ子になっていないことを仮定して task_group_context の詳細については説明していませんでした。ここで、詳細を説明します。

インテル® スレッディング・ビルディング・ブロック (インテル® TBB) のアルゴリズムは、ユーザーがアルゴリズム・テンプレートに提供したコードの断片を実行する task オブジェクトを作成することにより実行されます。デフォルトでは、これらの task オブジェクトはアルゴリズムにより作成される task_group_context と関連付けられます。入れ子のインテル® TBB アルゴリズムは、これらの task_group_context オブジェクトのツリーを作成します。task_group_context をキャンセルすると、その子 task_group_context オブジェクトがすべてキャンセルされ、結果的にそのすべての子孫がキャンセルされます。つまり、アルゴリズムと、そのアルゴリズムが呼び出したアルゴリズムをすべて、1 つのリクエストでキャンセルすることができます。

例外は上向きに伝わります。キャンセルは下向きに伝わります。例外が発生すると、入れ子になっている計算も停止されます。例えば、次の図のツリーについて考えてみます。各ノードはアルゴリズムとその task_group_context を表していると考えてください。

task_group_context のツリー

C でアルゴリズムが例外をスローし、例外をキャッチするノードがないことを仮定します。インテル® TBB は、次のように、例外を上方向に伝え、関連するサブツリーを下方向にキャンセルします。

  1. C における例外の制御:

    1. C の例外をキャプチャーします。

    2. C のタスクをキャンセルします。

    3. C から B に例外をスローします。

  2. B における例外の制御:

    1. B の例外をキャプチャーします。

    2. B のタスクをキャンセルし、下向きに D に伝えます。

    3. B から A に例外をスローします。

  3. A における例外の制御:

    1. A の例外をキャプチャーします。

    2. A のタスクをキャンセルし、下向きに E、F、G に伝えます。

    3. A から上向きに例外をスローします。

コードが (任意のレベルで) 例外をキャッチすると、インテル® TBB は例外をそれ以上伝えません。例えば、parallel_for のボディーの外部に例外が伝えられなければ、ほかの反復はキャンセルされません。

キャンセルが下方向にアルゴリズムに伝えられるのを防ぐには、スタックに「孤立した」 task_group_context を構築して、明示的にアルゴリズムに渡します。次のコードの太字の部分です。簡潔に表現するため、サンプルは C++11 ラムダ式を使用しています。

#include "tbb/tbb.h"
 
bool Data[1000][1000];
 
int main() {
    try {
        parallel_for( 0, 1000, 1, 
            []( int i ) {
                task_group_context root(task_group_context::isolated);
                parallel_for( 0, 1000, 1,
                   []( int  ) {
                       Data[i][j] = true;
                   },
                   root);
                throw "oops";
            });
    } catch(...) {
    }
    return 0;
}

サンプルは、外部ループ i と内部ループ j の 2 つの並列ループを実行します。孤立した task_group_context root を作成することで、i ループのキャンセルが下方向の内部ループに伝えられなくなります。例外が外部ループに伝えられると、保留中の outer の反復はキャンセルされますが、(開始した外部の反復の) 内部の反復はキャンセルされません。そのため、プログラムが完了したときに、Data の列は反復 i をすべて実行したかどうかに依存して異なりますが、列の内部の要素は false または true のどちらか一方になります。

青の部分を削除すると、内部ループにキャンセルが伝えられるようになります。この場合、Data の列に truefalse の両方の値が含まれるようになります。

関連情報