我是openMP的新手,但我正在尝试编写一个简单的程序来并行生成矩阵的条目,即对于N×M矩阵A,让A(i,j)= i * j。下面列出了一个最小的例子:
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
int main(int argc,
char **argv)
{
int i, j, N, M;
N = 20;
M = 20;
int* A;
A = (int*) calloc(N*M, sizeof(int));
// compute entries of A in parallel
#pragma omp parallel for shared(A)
for (i = 0; i < N; ++i){
for (j = 0; j < M; ++j){
A[i*M + j] = i*j;
}
}
// print parallel results
for (i = 0; i < N; ++i){
for (j = 0; j < M; ++j){
printf("%d ", A[i*M + j]);
}
printf("\n");
}
free(A);
return 0;
}
结果并不总是正确的。理论上,我只是并行化外部循环,for循环的每次迭代都不会修改其他迭代将修改的条目。但我不知道如何将其转换为openMP。当对矢量数组执行类似的过程(即只有一个用于循环)时,似乎没有问题,例如。
#pragma omp parallel for
for (i = 0; i < N; ++i)
{
v[i] = i*i;
}
有人可以向我解释如何解决这个问题吗?
答案 0 :(得分:3)
在这种情况下的问题是线程之间j
共享与内部循环的控制流混淆。默认情况下,在并行区域外声明的变量是 shared ,而在并行区域内声明的变量是 private 。
遵循一般规则尽可能在本地声明变量。在for循环中,这意味着:
#pragma omp parallel for
for (int i = 0; i < N; ++i) {
for (int j = 0; j < M; ++j) {
这使得对代码的推理变得更加容易 - 而且默认情况下OpenMP代码大多是正确的。 (注意A
默认是共享的,因为它是在外面定义的。)
或者您可以手动指定private(i,j) shared(A)
- 这更明确,可以帮助初学者。但是它会产生冗余并且也可能很危险:private
变量未初始化,即使它们在并行区域之外具有有效值也是如此。因此,我强烈建议使用隐式默认方法,除非高级用法需要。
答案 1 :(得分:1)
根据例如这
http://supercomputingblog.com/openmp/tutorial-parallel-for-loops-with-openmp/
在并行部分之外声明变量是危险的 它可以通过显式地使内循环的循环变量私有来解除。
为此,请更改此
#pragma omp parallel for shared(A)
到
#pragma omp parallel for private(j) shared(A)