2017-11-02 11 views
1

Game of Lifeをシミュレートする単純なプログラムを並列化するためにOpenMPを使用しようとしています。OpenMP:エラー: 'w.13'が並列を囲んで指定されていません

私は、以下の機能を持っている:私は、Windows 10上のbash上で、gcc-4.8 gameoflife.c -o gameoflife -std=gnu99 -O3 -fopenmpでそれをコンパイルしています

#define for_x for (int x = 0; x < w; x++) 
#define for_y for (int y = 0; y < h; y++) 
#define for_xy for_x for_y 

、および:

void evolve_parallel(void *u, int w, int h) 
{ 
    unsigned (*univ)[w] = u; 
    unsigned new[h][w]; 

    #pragma omp parallel for firstprivate(univ, new, w, h), collapse(2), default(none) 
    for_y for_x { 
     int n = 0; 
     for (int y1 = y - 1; y1 <= y + 1; y1++) 
      for (int x1 = x - 1; x1 <= x + 1; x1++) 
       if (univ[(y1 + h) % h][(x1 + w) % w]) 
        n++; 

     if (univ[y][x]) n--; 
     new[y][x] = (n == 3 || (n == 2 && univ[y][x])); 
    } 
    for_y for_x univ[y][x] = new[y][x]; 
} 

は、(ファイルの先頭)私のマクロがあります私はdefault(none)を削除する場合は、

gameoflife.c: In function ‘evolve_parallel’: 
gameoflife.c:131:13: error: ‘w.13’ not specified in enclosing parallel 
    if (univ[(y1 + h) % h][(x1 + w) % w]) 
      ^
gameoflife.c:126:10: error: enclosing parallel 
    #pragma omp parallel for firstprivate(univ, new, w, h), collapse(2), default(none) 
     ^

:gccのは私に次のエラーを与えますコードをコンパイルしますが、私はコードを変更し続けるとコンパイラーは私がいくつかの変数をprivateまたはfirstprivateとして宣言するのを忘れた場合に警告を発します。

明らかに、私はw.13という変数を持っていません。これは私が使用している外部変数ではありません。私のコードがコンパイルされていない理由を誰かが知っていますか?

答えて

0

これはgccのバグであり、最新バージョン(7.2)にはまだ存在していると思います。私はここで起こる疑い何

可変修飾可変長配列へのポインタが)型が大がアクセスされるたびに暗黙的にアクセスされた隠れ変数w.13を使用することです。ある意味では、コンパイラは次のようにこのコードを考える:再現する

// instead of unsigned (*univ)[w] ...; 
unsigned **univ ...; 
const int w.13 = w; 
.... 
// instead of univ[x][y] 
univ[x * w.13 + y] 

短いバージョン:

void foo(int n, int a[][n]) 
{ 
    #pragma omp parallel shared(a) default(none) 
    a[23][0] = 42; 
} 

バグを報告すること自由に感じ、または私はそうだろう。 default(none)を削除しなければならないと思います。代わりに以外のものを使用して、を変更することもできます。私は自分自身のために彼らの大ファンではありません。

あなたのコードには他にもいくつか問題があると言われています。これらの変数すべてでfirstprivateを使用するのではなく、代わりにsharedを使用することをお勧めします。 univ, w, hの場合のように、パラレル領域で何かが読み取られた場合は、それは安全に行うことができ、sharedである必要があります。 newは並列領域の結果であり、従って共有されるべきである。 private(およびfirstprivate)の内容は、パラレル領域の後に保存されません。 newが共有されることも安全です。なぜなら、各反復(スレッド)は別々の要素にアクセスするためです。

パフォーマンス上の理由から、ループの順序を元に戻す必要があります。これにより連続ケース(特にパラレルケース)が誤った共有を避けるのを助ける連続メモリアクセス(少なくともnew)が生成されます。

最後に、あなたの正気を保つことが好きなら:マクロをドロップします。彼らがあなたに与える苦痛と混乱のレベルは、彼らが提供する少しの利便性よりもはるかに大きなものです。私はそれを保証します - もしあなたが間違っていたらあなたのお金を返すことを約束します。

注:標準ではC99を参照していますが、OpenMP標準ではそのようなタイプの参照は見つかりませんでした。

+0

最初は共有されていましたが、コンパイラのエラーを見たとき、私はfirstprivateを試してみて、共有に戻すのを忘れました。私はそれを元に戻します。 パフォーマンスの問題について - 私はnewが 'new [y] [x]'としてアクセスされるので、ループの順番はOKだと思うので、最初のループはy以上、xは2以上です。 最後に、これは私のコードではなく、私はそれを並列化しているので、マクロは私が最初に得たものです。 –

関連する問題