taskq プラグマは、囲まれた作業 (タスク) 単位が実行される環境を指定します。最初に、taskq プラグマを実行するすべてのスレッド間の中から、1 つのスレッドが選択されます。概念的には、taskq プラグマは、選択したスレッドを実行する空のキューを生成し、次に、taskq ブロック内のコードがシングルスレッドで実行されます。他のすべてのスレッドは、この概念キューに作業がキューイングされるのを待ちます。task プラグマは、潜在的に異なるスレッドで実行される作業単位を指定します。taskq ブロック内に task プラグマが存在すると、task ブロックの内側のコードは、taskq に関連付けられている概念キューにキューイングされます。キューイングされたすべての作業が終了し、taskq ブロックの最後に達すると、概念キューはなくなります。
多くの制御構造体は、異なる作業反復と作業生成のパターンを表しているため、ワークキューイング・モデルで並列化可能です。次は、一般的なケースです。
while ループ
C++ 反復子
再帰関数
while ループ
while ループの各反復における計算が独立している場合、ループ全体が taskq プラグマに対する環境になります。while ループ本体内の文が、task プラグマで指定される作業単位になります。while ループの条件と制御変数への修正は、task ブロックの外側に置かれ、データを制御変数に依存させるようシーケンシャルに実行されます。
C++ 反復子
C++ STL (標準テンプレート・ライブラリー) 反復子は、前述した while ループに非常に類似しています。STL にストアされるデータの演算は、すべてのデータに対する反復動作から独立しているからです。データが独立している演算の場合、その演算は、作業の反復がシーケンシャルであれば、並列に処理されます。このタイプの while ループ並列処理は、ループの標準 OpenMP* の for ループのワークシェアリングを一般化したものです。for ループのワークシェアリングでは、ループの増分演算が反復子で、ループの本体が作業単位です。しかし、for ループ反復子の変数は、大抵クローズされたフォームを持つため、その変数は並列に処理することができ、シーケンシャルなステップを回避できます。
再帰関数
再帰関数もまた、並列に反復処理を指定するために使用できます。そのメカニズムは、sections プラグマを使用する並列処理を指定するのに類似していますが、より柔軟性があります。taskq と task プラグマ間に任意のコードを置くことができ、関数の再帰的入れ子で、taskq キューの概念ツリーをビルドできるためです。taskq プラグマの再帰的入れ子は、入れ子された OpenMP 並列領域のように動作する OpenMP のワークシェアリング構造の概念を拡張したものです。入れ子された並列領域のように、入れ子された各ワークキューイング構造は新しいインスタンスで 1 つのスレッドに検出されます。しかし主な相違点は、入れ子されたワークキューイング構造は新しいスレッドやチームを生成しないことです。むしろチームからスレッドを再利用します。これにより、動的環境で、マルチアルゴリズム並列処理を容易にし、並列処理の各レベルでスレッドの数を確保する必要がなくなり、トップレベルだけで済ますことができます。その時点から、大量の作業量が内側のレベルで発生すると、外側のレベルからアイドルスレッドは、その作業の終了を支援することができます。例えば、1 つのスレッドに各インカミング・リクエストを処理させ、多くのスレッドがインカミング・リクエストを待機している状態は、サーバー環境では非常に一般的です。特定のリクエストにおいて、スレッドが処理を開始する時点では、そのサイズが明らかではないことがあります。スレッドが、入れ子されたワークキューイング構造を使用し、内側の構造が開始された後にリクエストのスコープが大きくなると、外側の構造のスレッドは、リクエストを終了するために内側の構造に簡単に移動できます。
ワークキューイング・モデルはシーケンシャルなセマンティクスを保持するように設計されているため、同期化は taskq ブロックのセマンティクスに固有のものです。taskq 構造を検出したスレッドの taskq ブロックの完了時に暗黙的なチームバリアがあるため、taskq ブロック内で指定されたすべてのタスクの実行が終了したことを確認できます。この taskq バリアは、オリジナルプログラムのシーケンシャル・セマンティクスを実行します。OpenMP ワークシェアリング構造のように、タスクブロック間、あるいはタスクブロックのコードと、タスクブロック外の taskq ブロックのコード間で、依存性が存在しないこと、または適切に同期されることを確認する必要があります。
文法、セマンティクスおよび構文は、OpenMP ワークシェアリング構造と同じように設計されています。OpenMP ワークシェアリング構造で有効な構文のほとんどは、ワークキューイング・プラグマでも、適切な意味を持ちます。
この構造は、次のような構文を使用します。
構文 |
---|
#pragma intel omp taskq [clause[[,]clause]...] structured-block |
clause (節) は次のいずれかです。
private (variable-list)
firstprivate (variable-list)
lastprivate (variable-list)
reduction (operator :variable-list)
ordered
nowait
次の表は、サポートされている節のリストです。
節 |
説明 |
---|---|
private |
private 節は、taskq の variable-list にある各オブジェクトの default-constructed バージョンの private を生成します。囲まれた各タスクで、captureprivate も含みます。各変数に参照されるオリジナルのオブジェクトは、構造に入る時点で中間値を持ちます。構造の動的範囲内では、オブジェクトは変更してはなりません。そして、構造から出る時点で中間値を持ちます。 |
firstprivate |
firstprivate 節は、taskq の variable-list に各オブジェクトにある copy-constructed バージョンの private を生成します。囲まれた各タスクで、captureprivate も含みます。各変数に参照されるオリジナルのオブジェクトは、構造の動的範囲内では、変更してはなりません。そして、構造から出る時点で中間値を持ちます。 |
lastprivate |
lastprivate 節は、taskq の variable-list にある各オブジェクトの default-constructed バージョンの private を生成します。囲まれた各タスクで、captureprivate も含みます。各変数に参照されるオリジナルのオブジェクトは、構造に入る時点で中間値を持ちます。構造の動的範囲内では、オブジェクトは変更してはなりません。そして、タスクの実行が終了した後に、オブジェクトは囲まれた最後のタスクからのオブジェクトの値をコピー割り当てされます。 |
reduction |
reduction 節は、variable-list にある各オブジェクトの囲まれたタスク構造で与えられた演算子を持つリダクション演算を実行します。operator と variable-list は、OpenMP 仕様と同じように定義されます。 |
ordered |
ordered 節は、オリジナルのシーケンシャル実行順序で、囲まれた task 構造で、ordered コンストラクターを実行します。ordered と結合される taskq 宣言子には ordered 節がなければなりません。 |
nowait |
nowait 節は、taskq の最後にある暗黙的なバリアを削除します。taskq 構造にキューされたすべての task 構造が処理される前に、スレッドは taskq 構造を終了できます。 |
この構造は、次のような構文を使用します。
構文 |
---|
#pragma intel omp task [clause[[,]clause]...] structured-block |
clause (節) は次のいずれかです。
private( variable-list )
captureprivate( variable-list )
次の表は、サポートされている節のリストです。
節 |
説明 |
---|---|
private |
private 節は、task の variable-list にある各オブジェクトの default-constructed バージョンの private を生成します。変数に参照されるオリジナルのオブジェクトは、構造に入る時点で中間値を持ちます。構造の動的範囲内では、オブジェクトは変更してはなりません。そして、構造から出る時点で中間値を持ちます。 |
captureprivate |
captureprivate 節は、task がエンキューされた時点で、task の variable-list に各オブジェクトにある copy-constructed バージョンの private を生成します。各変数に参照されるオリジナルのオブジェクトは、その値を保持しますが、task 構造の動的範囲内では、変更してはなりません。 |
この構造は、次のような構文を使用します。
構文 |
---|
#pragma intel omp parallel taskq [clause[[,]clause]...] structured-block |
clause (節) は次のいずれかです。
if(scalar-expression)
num_threads(integer-expression)
copyin(variable-list)
default(shared | none)
shared(variable-list)
private(variable-list)
firstprivate(variable-list)
lastprivate(variable-list)
reduction(operator : variable-list)
ordered
clause (構文) は、parallel および taskq 構造と同様です。