OpenMP* REDUCTION 変数の不適切な使用

REDUCTION 変数が領域から呼び出されるサブルーチンで名前によって参照されています。

REDUCTION 節は、再帰的な数学的計算を並列で行う際に使用されます。それぞれのタスクでプライベートな一時変数が作成され、 領域の最後で、これらの一時変数が結合されて外部変数を更新します。例えば、すべての一時変数を加算して最終合計値を形成します。構造内では、外部変数への参照が一時変数への参照に置き換えられます。これにより、変数が共有された場合に並列モードで発生するであろうデータ競合を排除しながら、並列モードとシーケンシャル・モードのセマンティクスが同じになるようにします。

ただし、この変換は完全ではありません。構造の実行中にスレッドが外部変数にアクセスする方法はいくつもあります。通常、これは並列モードとシーケンシャル・モードで異なる実行セマンティクスをもたらし、データ競合を発生させ、OpenMP* 規則に違反します。一般に、コンパイラーは構造境界内にある外部変数への名前参照のみ置き換えますが、これによりすべての種類のデータ参照がキャッチされるわけではありません。

特に、サブルーチンが構造内から呼び出され、そのサブルーチンが構造内の REDUCTION 節にリストされている変数を名前で参照している場合、この参照はスレッドごとの一時変数ではなく外部変数にバインドされます。この診断は、このような誤った使用法をレポートします。

この不具合を修正する 1 つの方法として、外部変数参照をパラメーターに置き換える方法があります。これにより、すべての呼び出し位置で外部変数がサブルーチンに渡されます。サブルーチンが外部変数を編集する必要がある場合、パラメーターは参照によって渡されなければなりません。

また、構造の動的範囲内でポインターを通じて REDUCTION 変数にアクセスする際にも注意が必要です。ポインターが構造外で値を取得した場合、その値は (REDUCTION 変数ではなく) 外部変数のものである可能性があり、前述のような問題が発生します。

ID

問題箇所

説明

1

不正なメモリーアクセス

PRIVATE 変数がアクセスされた場所

          
#include <stdio.h>
#include <omp.h>

int a;

void bad_subroutine()
{
   a += 2; // BAD: sets the value of the outer variable by name
}

void good_subroutine(int &t)
{
   t += 2; // GOOD: a is accessed via reference parameter
}

int main(int argc, char **argv)
{
    int i;

    #pragma omp parallel for reduction(+:a)
    for (i = 1; i < 10; i++) {
        a += 2; // reference to reduction temporary
        bad_subroutine();
        good_subroutine(a);
    }
    printf("%d\n", a);
    
    return 0;
}
        

© 2010 Intel Corporation. 無断での引用、転載を禁じます。