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

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

PRIVATE 節は、並列領域を実行するスレッド間のデータ共有を制御するのに使用されます。PRIVATE 節に変数をリストすることにより、その構造を実行する各スレッドに対して、外部変数と同じ型のスレッド・プライベートな一時変数が作成され、 構造内では、外部変数への参照が一時変数への参照に置き換えられます。これにより、変数が共有された場合に並列モードで発生するであろうデータ競合を排除しながら、並列モードとシーケンシャル・モードのセマンティクスが同じになるようにします。

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

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

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

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

ID

問題箇所

説明

1

不正なメモリーアクセス

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

2

OpenMP* 宣言

変数が PRIVATE として指定された構造


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

class myClass {
int ii;
public:
   myClass() { ii = 0; };
   void set(int x) { ii = x; };
   int  get() { return ii; };
};

myClass a;

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

void good_subroutine(myClass &t)
{
   t.set(3); // GOOD: a is accessed via reference parameter
}

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

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

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