You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ifort下OpenMP嵌套DO循环并行化结果异常问题求助

Fortran 77 OpenMP嵌套DO循环并行化结果异常的解决方案

问题核心原因

你的代码中,全局变量qs01被所有线程共享,当多个线程同时执行qs01=qs01+...的累加操作时,会出现数据竞争:线程A读取qs01的值还没完成写入,线程B已经读取了旧值并进行计算,最终导致累加结果被覆盖、错乱,这就是线程数增加后结果异常的根本原因。单线程时没有竞争,所以结果正常。

修复方案

方法1:使用OpenMP的REDUCTION子句(推荐)

在PARALLEL DO指令中添加REDUCTION(+:qs01),让OpenMP自动为每个线程创建qs01的私有副本,并行计算完成后再将所有线程的副本值累加到全局的qs01中,避免竞争。

修改后的代码片段:

C$OMP  PARALLEL DO DEFAULT(SHARED), PRIVATE(kp,i1,kt,j,kf,k,k2), REDUCTION(+:qs01)
      
      do kp=1,np
      do i1=1,nleg1
    do kt=1,nt
      do j=1,nleg
    do kf=1,nf
      do k=1,nleg

      ap=(cp(kp+1)-cp(kp))*dx1(i1)*0.5d0+(cp(kp+1)+cp(kp))*0.5d0
      atp=(ct(kt+1)-ct(kt))*dx2(j)*0.5d0+(ct(kt+1)+ct(kt))*0.5d0
      aphp=(cf(kf+1)-cf(kf))*dx3(k)*0.5d0+(cf(kf+1)+cf(kf))*0.5d0
    

C 'LES COMP DES P ( PX, PY, PZ ) et ( Ki + P )'
      apx=ap*dsin(atp)*dcos(aphp)
      apy=ap*dsin(atp)*dsin(aphp)
      apz=ap*dcos(atp)
    
C VECTEUR Ki+P
      akpx= akix + apx
      akpy= akiy + apy
      akpz= akiz + apz

c       print*,akpx,akpy,akpz
C VECTEUR K01=0.5*(ks-k1) et K01+P


      akp01x=ak01x-apx
      akp01y=ak01y-apy
      akp01z=ak01z-apz
         
C -------------------------------------------------
C--                       ELEMENT DE MATRICE
      t1=tcs(alpha,az,-apx,-apy,-apz,akex,akey,akez,1) *fa(alpha,0) 
      qj01=tcs(al0,az,akpx,akpy,akpz,aksx,aksy,aksz,1)
     $*q0s(al0,az01,akp01x,akp01y,akp01z,ak01x,ak01y,ak01z)

      qj0=q0s(al0,az,akpx,akpy,akpz,aksx,aksy,aksz)
     $*tcs(al0,az01,akp01x,akp01y,akp01z,ak01x,ak01y,ak01z,1)

c   print*,t1
    tj1=t1*(qj01-qj0)

    

C The Integration Over P

    qs01=qs01+aw1(i1)*aw2(j)*aw3(k)*ap*ap*(cf(kf+1)-cf(kf))
     $*(cp(kp+1)-cp(kp))*(ct(kt+1)-ct(kt))*dsin(atp)*tj1/8.d0

      enddo
      enddo
      enddo
    enddo
    enddo
    enddo
C$OMP END PARALLEL DO

方法2:手动使用私有变量累加(兼容旧版编译器)

如果你的编译器不支持REDUCTION子句,可以手动声明线程私有累加变量,并行计算结束后合并结果:

real*8 qs01, qs01_private ! 声明私有累加变量
C$OMP  PARALLEL DEFAULT(SHARED), PRIVATE(kp,i1,kt,j,kf,k,k2,qs01_private)
      qs01_private = 0.0d0 ! 每个线程初始化私有变量
C$OMP DO
      do kp=1,np
      do i1=1,nleg1
    do kt=1,nt
      do j=1,nleg
    do kf=1,nf
      do k=1,nleg

      ! 中间计算代码不变...

    qs01_private=qs01_private+aw1(i1)*aw2(j)*aw3(k)*ap*ap*(cf(kf+1)-cf(kf))
     $*(cp(kp+1)-cp(kp))*(ct(kt+1)-ct(kt))*dsin(atp)*tj1/8.d0

      enddo
      enddo
      enddo
    enddo
    enddo
    enddo
C$OMP END DO
C$OMP CRITICAL
      qs01 = qs01 + qs01_private ! 临界区安全合并结果
C$OMP END CRITICAL
C$OMP END PARALLEL

额外注意事项

  • 确认akix, akiy, akiz, ak01x, ak01y, ak01z等变量是只读的共享变量,不会被线程修改,否则也会引发竞争。
  • 代码中声明的k2变量未被使用,可以删除该私有声明,避免冗余。

内容的提问来源于stack exchange,提问作者ggt bnd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 12:57:19