次の方法で共有


2.7.2.6 reduction

この句は、演算子 op を使用して、variable-list 内に現れるスカラー変数に対してリダクションを実行します。 reduction 句の構文は次のとおりです。

reduction(op:variable-list)

リダクションは、通常、次のいずれかの形式のステートメントに対して指定されます。

x     =  x     op     expr
x     binop=  expr
x     =  expr     op     x            (except for subtraction)
x++
++x
x--
--x

それぞれの文字について以下に説明します。

  • x
    list 内で指定されているリダクション変数の 1 つ。

  • 変数の一覧
    コンマ区切り形式のスカラー リダクション変数のリスト。

  • expr
    x を参照しないスカラー型の式。

  • op
    オーバーロードされた演算子ではなく、+、*、-、&、^、|、&&、または || のいずれかです。

  • binop
    オーバーロードされた演算子ではなく、+、*、-、&、^、または | のいずれかです。

reduction 句の例を次に示します。

#pragma omp parallel for reduction(+: a, y) reduction(||: am)
for (i=0; i<n; i++) {
   a += b[i];
   y = sum(y, c[i]);
   am = am || b[i] == c[i];
}

例に示されているように、演算子は関数呼び出し内部に隠されている場合があります。 開発者は、リダクション演算が、reduction 句内の演算子の指定と合うように注意する必要があります。

この例では || 演算子の右側のオペランドに副作用はありませんが、副作用は許可されており、注意して使用する必要があります。 このコンテキストでは、ループの順次実行中に発生しないと保証されている副作用についても並列実行中に発生することがあります。 これは、反復処理の実行順序が順不同であるためです。

演算子を使用して、リダクション用にコンパイラが使用するプライベート変数の初期値が決定され、終了演算子が決定されます。 演算子を明示的に指定することにより、リダクション ステートメントを、そのコンストラクトの構文範囲外で使用できます。 reduction 句はいくつでもディレクティブに指定できますが、1 つの変数はそのディレクティブの 1 つの reduction 句にしか現れることができません。

private 句が使用されているかのように、variable-list 内の各変数のプライベート コピーが作成されます。 プライベート コピーは、演算子に従って初期化されます (以下の表を参照してください)。

reduction 句が指定されている領域の最後で、元のオブジェクトが、指定された演算子を使用して各プライベート コピーの最終値とその元の値を結合した結果を反映するように、更新されます。 リダクション演算子は、すべて (減算を除いて) 結合可能であり、コンパイラは最終値の計算を自由に再結合できます。 減算のリダクションの部分的な結果は、加算されて最終値を形成します。

最初のスレッドが変数を含んでいる句に到達すると、元のオブジェクトの値は未定義状態になり、これが、リダクションの計算が完了するまで、維持されます。 通常、計算は、そのコンストラクトの終了点で完了しますが、reduction 句が、nowait も適用されるコンストラクトで使用される場合には、すべてのスレッドが reduction 句を完了するためにバリア同期が実行されるまで、元のオブジェクトの値は未定義状態のままでいます。

以下の表では、有効な演算子とそれぞれ標準的な初期値を示します。 実際の初期値は、リダクション変数のデータ型と一致します。

演算子

初期化

+

0

*

1

-

0

&

~0

|

0

^

0

&&

1

||

0

reduction 句に対する制限は次のとおりです。

  • reduction 句内の変数の型は、リダクション演算子に対して有効である必要があります。ただし、ポインター型と参照型は許可されません。

  • reduction 句で指定される変数は const 修飾型になれません。

  • 並行領域内部でプライベートな変数、または parallel ディレクティブの reduction 句内の変数を、parallel コンストラクトにバインドされる work-sharing ディレクティブの reduction 句に指定することはできません。

    #pragma omp parallel private(y)
    { /* ERROR - private variable y cannot be specified
                 in a reduction clause */
       #pragma omp for reduction(+: y)
       for (i=0; i<n; i++)
          y += b[i];
    }
    
    /* ERROR - variable x cannot be specified in both
               a shared and a reduction clause */
    #pragma omp parallel for shared(x) reduction(+: x)