基于求和的 OpenMP

OpenMP over Summation

我一直在尝试将 OpenMP 应用于两个嵌套循环内的简单求和运算,但到目前为止它产生了不正确的结果。我一直在 here and here, also in here 中四处张望。所有人都建议使用 reduction 子句,但它不适用于我的情况,因为它会产生导致 segmentation fault.

的非常大的数字

我也试过here and my own question 中的这种方式,已经解决了。两者都不使用 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

我认为您对 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 都不会对应于您在串行版本中期望的正确索引.


正如 Vladimir 在他的评论中建议的那样,您可以直接计算索引,因为您只是在内循环中递增它:

!$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