OpenMP:错误:’w.13’未在封闭并行中指定

我正在尝试使用OpenMP来并行化一个模拟生命游戏的简单程序。

我有以下function:

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]; } 

我的宏(位于文件顶部)是:

 #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 

我正在使用gcc-4.8 gameoflife.c -o gameoflife -std=gnu99 -O3 -fopenmp编译它,在Windows 10上的bash上,gcc给了我以下错误:

 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) ^ 

如果我删除default(none) ,代码编译,但我想保留它,以便当我继续更改代码时,如果我忘记声明某些变量private或firstprivate,编译器会提醒我。

显然,我没有一个名为w.13的变量,这不是我正在使用的一些外部变量。 有人知道为什么我的代码没有编译吗?

我认为这是gcc中的一个错误,它仍然存在于最新版本(7.2)中。

我怀疑这里发生的是可变修改 (指向可变长度数组 )类型使用隐藏变量w.13 ,只要访问univ就会隐式访问它。 从某种意义上说,编译器会考虑这样的代码:

 // 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 ,那么它可以安全且应该sharednew是并行区域的结果,因此也应该共享。 private (和firstprivate )变量的内容在并行区域后不会保留。 共享new也是安全的,因为每次迭代(以及线程)都访问一个单独的元素。

出于性能原因,您应该恢复循环的顺序。 这将产生连续的内存访问(至少是new ),这有助于串行情况,但特别是并行情况,以避免错误共享。

最后,如果你想保持理智: 放弃宏 。 他们对你造成的痛苦和困惑程度比他们提供的一点点便利要大许多个数量级。 我保证 – 如果我错了,我保证你甚至可以拿回你的钱。

注意:虽然标准确实参考了C99,但我在OpenMP标准中找不到对这些类型的任何引用。