OpenMP over Summation

时间:2015-05-24 15:19:38

标签: parallel-processing fortran openmp fortran90 gfortran

我一直试图在两个嵌套循环内的简单求和操作中应用OpenMP,但到目前为止它产生了不正确的结果。我一直在herehere以及here中四处寻找。所有建议都使用reduction子句,但是通过生成非常大的数字导致segmentation fault,它对我的​​情况不起作用。

我也试过这种方式发布在here和我自己的问题here已经解决了。两者都不使用reduction,只是将求和变量设置为shared,但它也会产生不正确的结果。有什么东西我错过了吗?何时使用reduction而不是在面对求和操作时使用它?

使用reduction子句

的代码
index = 0
!$OMP PARALLEL DO PRIVATE(iy,ix) REDUCTION(:+index)
do iy = 1, number(2)
    do ix = 1, number(1)
        index = index + 1
        xoutput(index)=xinput(ix)
        youtput(index)=yinput(iy)
    end do
end do
!$OMP END PARALLEL DO

不使用reduction子句的代码

index = 0
!$OMP PARALLEL DO PRIVATE(iy,ix) SHARED(index)
do iy = 1, number(2)
    do ix = 1, number(1)
        index = index + 1
        xoutput(index)=xinput(ix)
        youtput(index)=yinput(iy)
    end do
end do
!$OMP END PARALLEL DO

1 个答案:

答案 0 :(得分:4)

我认为你对reduction条款的作用有误解......

REDUCTION(+:index)

表示您最终会得到正确的总和index 。在迭代的每个步骤中,每个胎面将具有不同的版本,具有不同的值!因此,减少不适合在并行部分期间管理数组索引。

让我试着说明一下......

以下循环

!$OMP PARALLEL DO PRIVATE(iy) REDUCTION(+:index)
do iy = 1, number(2)
  index = index + 1
end do
!$OMP END PARALLEL DO

(或多或少)等同于

!$OMP PARALLEL PRIVATE(iy, privIndex) SHARED(index)
!$OMP DO
do iy = 1, number(2)
  privIndex = privIndex + 1
end do
!$OMP END DO

!$OMP CRITICAL
index = index + privIndex
!$OMP END CRITICAL
!$OMP END PARALLEL

您可以看到,在循环期间,所有线程都处理不同的变量privIndex,这些变量对该线程是私有的,并计算本地(部分)总和。最后,使用critical部分获取总和以避免竞争条件。

这可能不是编译器的作用,但是它可以让您了解减少的工作原理:在第一个循环中,privIndex中的任何一点都不会对应于您在串行版本中所期望的正确索引。

正如弗拉基米尔在评论中建议的那样,你可以直接计算索引,因为你只是在内循环中递增它:

!$OMP PARALLEL DO PRIVATE(iy,ix, index)
do iy = 1, number(2)
    do ix = 1, number(1)
        index = (iy-1)*number(1) + ix
        xoutput(index)=xinput(ix)
        youtput(index)=yinput(iy)
    end do
end do
!$OMP END PARALLEL DO