openmp共享还是什么都没有。私有与未初始化

时间:2019-02-23 16:23:31

标签: c++ c parallel-processing openmp

这两个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 

1 个答案:

答案 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;
  }
}

默认情况下,xy是共享的。因此,如果没有private,其行为将有所不同(并且会出现错误,因为所有线程都将修改同一全局可访问的变量xy,而无需进行原子访问)。

  

与不使用private(x,y)一样,因为x和y未初始化?

xy的初始化无关紧要,重要的是声明它们的位置。为了确保行为正确,必须将它们设置为私有,并且在循环中使用xy之前,应正确设置代码。