首页 > 解决方案 > 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 行没有 shared(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 

标签: c++cparallel-processingopenmp

解决方案


这两种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行为将会有所不同(并且有问题,因为所有线程都将修改相同的全局可访问变量x并且y没有原子访问)。

与没有 private(x,y) 相同,因为 x 和 y 未初始化?

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


推荐阅读