OpenMP* THREADPRIVATE 配列の不適切な使用

並列領域間でのデータの受け渡しに THREADPRIVATE 配列が誤って使用されています。

THREADPRIVATE 宣言子は、変数を複製して、それぞれのスレッドで独自のコピーを持つように指定します。OpenMP* は、予期できない方法でスレッドに処理を割り当てるため、特定のスレッドのプライベート・コピーの値がスケジューリング・ポイントの後に中間値となります。このエラー診断は、値が中間状態にあるときに THREADPRIVATE 変数が読み取られた場合にレポートされます。

THREADPRIVATE 変数の値は、主に 2 つの場合に中間状態となります。1 つ目は、変数が変更された並列領域を終了した時点です。ここでの問題は、どのスレッドがどの代入を実行するのか予測することが一般に不可能であることです。もう 1 つは、並列領域を開始する時点です。ここでの問題は、どのスレッドが領域を実行するチームに参加するのか予測することが一般に不可能であることです。並列領域に COPYIN 節がある場合、チームの各メンバーのプライベート・コピーは、エントリー時にマスタースレッドの変数の値で初期化されます。

このメッセージは、特に、ある並列領域で THREADPRIVATE 配列変数に値が代入され、別の並列領域でその値が読み取られる際に、2 つの参照のインデックス指定が異なる場合に出力されます。例えば、あるループは "a[i]" を参照し、別のループは "a[i+1]" を参照する場合などです。このような状況では、両方のループで同じスレッドが同じ配列要素にアクセスするかどうかは定かではありません。

通常、このエラーは指摘された場所での THREADPRIVATE 変数の使用法が適切でないことを示します。並列領域を再編成して個別の領域で行われる操作を統合するか、または THREADPRIVATE 変数を使用せずに 2 つの並列領域間のデータを平坦化する必要があります。

ID

問題箇所

説明

1

不正なメモリーアクセス

値が参照された場所

2

OpenMP* 宣言

値が以前に定義された場所

3

OpenMP* 宣言

値が以前に定義された領域


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

int a[1000];
#pragma omp threadprivate (a)

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

// Here we have the two parallel loops that will map loop interations
// to threads in exactly the same way, but the threadprivate
// array "a" cannot be used to pass values from the first loop to
// the second because the arrays are not indexed in the same way.
//
// For example, suppose even iterations are assigned to
// thread T1 and odd iterations are assigned to thread T2.
// Then the first loop will initialize the even elements
// of T1's copy of "a" and the odd elements of T2's copy.
// The second loop will also map even iterations to T1
// and odd iterations to T2.  However, because the second
// loop indexes "a" with "i+1", the even iterations, the
// ones executed by T1, will add the uninitialized odd
// elements of T1's copy of "a" to sum.  This behavior
// differs from what would happen in sequential mode.

#pragma omp parallel for
    for (i = 0; i < 1000; i++) {
        a[i] = i;
    }
#pragma omp parallel for reduction (+:sum)
    for (i = 0; i < 1000; i++) {
        if (i!=999)
            sum = sum + a[i+1]; // inconsistent index
    }
    printf("%d\n", sum);
    return 0;
}
        

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