openmp 共享或没有。私有与未初始化

rel*_*lot 2 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;
}
Run Code Online (Sandbox Code Playgroud)

和相同的代码但第 4 行没有 shared(sum) 因为 sum 已经初始化?

#pragma omp parallel for
for(int = 0; ....)
Run Code Online (Sandbox Code Playgroud)

openmp 中 private 的相同问题:

是

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

与没有 private(x,y) 一样,因为 x 和 y 没有初始化?

#pragma omp parallel for 
Run Code Online (Sandbox Code Playgroud)

Ala*_*got 5

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;
}
Run Code Online (Sandbox Code Playgroud)

在 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;
}
Run Code Online (Sandbox Code Playgroud)

减少创建一个隐藏的局部变量,以在每个线程中并行累积,并在线程销毁之前对共享变量执行这些局部总和的原子加法sum。

openmp 中 private 的相同问题:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

默认情况下,x和y是共享的。因此,没有 private行为会有所不同(并且有问题,因为所有线程都将修改相同的全局可访问变量x并且y没有原子访问)。

与没有 private(x,y) 一样,因为 x 和 y 没有初始化?

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