我正在尝试使用OpenMP来并行化一个模拟生命游戏的简单程序。
我有以下功能:
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
的变量,这不是我正在使用的一些外部变量。有人知道为什么我的代码没有编译吗?
答案 0 :(得分:1)
我认为这是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
的情况),那么它可以安全且应该是shared
。 new
是并行区域的结果,因此也应该共享。并行区域后不保留private
(和firstprivate
)变量的内容。共享new
也是安全的,因为每次迭代(以及线程)都访问一个单独的元素。
出于性能原因,您应该恢复循环的顺序。这将产生连续的内存访问(至少new
),这有助于串行情况,尤其是并行情况,以避免错误共享。
最后,如果你想保持理智:删除宏。他们对你造成的痛苦和困惑程度比他们提供的一点点便利要大许多个数量级。我保证 - 如果我错的话,我保证你甚至可以退还你的钱。
注意:虽然标准确实引用了C99,但我在OpenMP标准中找不到对这些类型的引用。