我一直试图在两个嵌套循环内的简单求和操作中应用OpenMP,但到目前为止它产生了不正确的结果。我一直在here和here以及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
答案 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