这两个openmp实现之间有区别吗?
float dot_prod (float* a, float* b, int N)
{
float sum = 0.0;
#pragma omp parallel for shared(sum)
for (int i = 0; i < N; i++) {
#pragma omp critical
sum += a[i] * b[i];
}
return sum;
}
和相同的代码,但是第4行没有共享(sum),因为sum已经被初始化了?
#pragma omp parallel for
for(int = 0; ....)
在openmp中对私人有相同的问题:
是
void work(float* c, int N)
{
float x, y; int i;
#pragma omp parallel for private(x,y)
for (i = 0; i < N; i++)
{
x = a[i]; y = b[i];
c[i] = x + y;
}
}
与不使用private(x,y)一样,因为x和y未初始化?
#pragma omp parallel for
答案 0 :(得分:4)
这两个openmp实现之间有区别吗?
float dot_prod (float* a, float* b, int N)
{
float sum = 0.0;
# pragma omp parallel for shared(sum)
for (int i = 0; i < N; i++) {
#pragma omp critical
sum += a[i] * b[i];
}
return sum;
}
在openMP中,在并行作用域之外声明的变量为shared
,除非它被显式呈现为private
。
因此,shared
声明可以省略。
但是您的代码远非最佳。它可以工作,但比起顺序执行它要慢得多,因为critical
会强制执行顺序处理,并且创建关键节的时间成本很高。
正确的实现将使用reduction
。
float dot_prod (float* a, float* b, int N)
{
float sum = 0.0;
# pragma omp parallel for reduction(+:sum)
for (int i = 0; i < N; i++) {
sum += a[i] * b[i];
}
return sum;
}
约简创建一个隐藏的局部变量,以在每个线程中并行累积,然后在线程销毁之前对共享变量sum
进行这些局部和的原子加法。
在openmp中对私人有相同的问题:
void work(float* c, int N)
{
float x, y; int i;
# pragma omp parallel for private(x,y)
for (i = 0; i < N; i++)
{
x = a[i]; y = b[i];
c[i] = x + y;
}
}
默认情况下,x
和y
是共享的。因此,如果没有private
,其行为将有所不同(并且会出现错误,因为所有线程都将修改同一全局可访问的变量x
和y
,而无需进行原子访问)。
与不使用private(x,y)一样,因为x和y未初始化?
x
和y
的初始化无关紧要,重要的是声明它们的位置。为了确保行为正确,必须将它们设置为私有,并且在循环中使用x
和y
之前,应正确设置代码。