我对Fortran和OpenMP都比较新,但我正在努力适应。我有一段用于计算变异图的代码,现在想要并行化它。然而,我似乎遇到了竞争条件,因为一些结果会出现千分之一左右的偏差。
问题似乎是关于约简操作。使用OpenMP约简可以正常工作并给出正确的结果,但这并不是理想的解决方案,因为这些约简实际上发生在另一个子程序中(我将相关行复制到了OpenMP循环中进行测试)。因此,我将约减操作放入CRITICAL部分但没有成功。有趣的是,问题只会在实数情况下出现,而整数则不受影响。我已经考虑过加法的顺序是否有影响,但它们不应该产生这么大的误差。
为了确认,我将并行do中的所有内容都放在ORDERED块中,这当然会给出正确的结果(尽管没有任何加速)。我还尝试将所有内容放在CRITICAL部分内,但由于某种原因,这并没有给出正确的结果。我的理解是,OpenMP将在进入/退出CRITICAL部分时刷新共享变量,因此不应该存在任何缓存问题。
所以我的问题是:为什么在这种情况下CRITICAL部分无法正常工作?
以下是我的代码。除了np,tm,hm和gam之外,所有共享变量都是只读的。
编辑:我试图通过将do循环替换为相同范围内的随机整数(即生成一对i,j在循环中;如果它们被“访问”,则产生新的随机数)来模拟多个线程引起的随机性,但出乎意料的是结果匹配了。然而,进一步检查发现我忘记给RNG提供种子,结果只是巧合而已。多尴尬啊!
TL;DR: 结果的不一致性是由浮点值的排序引起的。使用双精度可以解决问题。
!$OMP PARALLEL DEFAULT(none) SHARED(nd, x, y, z, nzlag, nylag, nxlag, &
!$OMP& dzlag, dylag, dxlag, nvarg, ivhead, ivtail, ivtype, vr, tmin, tmax, np, tm, hm, gam) num_threads(512)
!$OMP DO PRIVATE(i,j,zdis,ydis,xdis,izl,iyl,ixl,indx,vrh,vrt,vrhpr,vrtpr,variogram_type) !reduction(+:np, tm, hm, gam)
DO i=1,nd
!$OMP CRITICAL (main)
! Second loop over the data:
DO j=1,nd
! The lag:
zdis = z(j) - z(i)
IF(zdis >= 0.0) THEN
izl = INT( zdis/dzlag+0.5)
ELSE
izl = -INT(-zdis/dzlag+0.5)
END IF
! ---- SNIP ----
! Loop over all variograms for this lag:
DO cur_variogram=1,nvarg
variogram_type = ivtype(cur_variogram)
! Get the head and tail values:
indx = i+(ivhead(cur_variogram)-1)*maxdim
vrh = vr(indx)
indx = j+(ivtail(cur_variogram)-1)*maxdim
vrt = vr(indx)
IF(vrh < tmin.OR.vrh >= tmax.OR. vrt < tmin.OR.vrt >= tmax) CYCLE
! ----- PROBLEM AREA -------
np(ixl,iyl,izl,1) = np(ixl,iyl,izl,1) + 1. ! <-- This never fails
tm(ixl,iyl,izl,1) = tm(ixl,iyl,izl,1) + vrt
hm(ixl,iyl,izl,1) = hm(ixl,iyl,izl,1) + vrh
gam(ixl,iyl,izl,1) = gam(ixl,iyl,izl,1) + ((vrh-vrt)*(vrh-vrt))
! ----- END OF PROBLEM AREA -----
!CALL updtvarg(ixl,iyl,izl,cur_variogram,variogram_type,vrt,vrh,vrtpr,vrhpr)
END DO
END DO
!$OMP END CRITICAL (main)
END DO
!$OMP END DO
!$OMP END PARALLEL
非常感谢您提前的帮助!