Fortran代码OpenMP并行化:线程安全与归约相关问题咨询
OpenMP并行化Fortran多循环代码的线程安全问题
该代码用于求解以下方程:A1(y,bp,kp) = \sum_i (B(y,yp_i)*C(Yp_i,Bp,Kp)*sum_j(D(bpp_j,kpp_j,yp_i,bp,kp)*A0(yp_i,bpp,kpp)))
我编写了如下多循环Fortran代码,用于基于其他数组计算矩阵A1:
do iKp = 1 , nK do iBp = 1 , nB do iY = 1 , nY tempibk = 0.0_dp do iYp = 1 , nY do iBK = 1 , nBK ibpp = bpi(iYp,iBp,iKp,iBK) ikpp = Kpi(iYp,iBp,iKp,iBK) tempibk(iYp) = tempibk(iYp) + D(iYp,iBp,iKp,iBK)*A0(iYp,ibpp,ikpp) enddo A1(iY,iBp,iKp) = A1(iY,iBp,iKp) + B(iY,iYp)*C(iYp,iBp,iKp)*tempibk(iYp)) end do end do end do end do
我希望使用OpenMP对该代码进行并行化,当前的疑问集中在代码的线程安全性上。我尝试的并行化代码如下:
!$OMP PARALLEL DO PRIVATE ( iY , iBp , iYp ,iKp, iBK, ibpp, ikpp, tempibk) SHARED(q1) do iKp = 1 , nK do iBp = 1 , nB do iY = 1 , nY tempibk = 0.0_dp do iYp = 1 , nY do iBK = 1 , nBK ibpp = bpi(iYp,iBp,iKp,iBK) ikpp = Kpi(iYp,iBp,iKp,iBK) tempibk(iYp) = tempibk(iYp) + D(iYp,iBp,iKp,iBK)*A0(iYp,ibpp,ikpp) enddo !$OMP ATOMIC A1(iY,iBp,iKp) = A1(iY,iBp,iKp) + B(iY,iYp)*C(iYp,iBp,iKp)*tempibk(iYp)) !$OMP END ATOMIC end do end do end do end do !$OMP END PARALLEL DO
我担心多个线程操作A1会引发竞争条件,即不同线程处理不同(iY, iYp, iBp, iKp)组合时可能同时访问并更新A1的同一元素,因此使用了ATOMIC指令。
问题解答
iBK循环内的代码是否需要设置临界区?
不需要。tempibk被声明为PRIVATE,每个线程都拥有独立的副本,iBK循环仅对当前线程私有的tempibk(iYp)执行累加操作,无共享数据竞争。此外,bpi、Kpi、D、A0均为只读共享数组,读取操作不会触发竞争,因此完全无需临界区。tempibk是否需要使用归约操作?A1是否也适合使用归约?
tempibk不需要归约:它是线程私有变量,每个线程独立计算自身的tempibk,用于后续更新A1,不存在跨线程合并的需求。且你在每个iY循环开头将tempibk初始化为0,私有变量的初始化是线程安全的,每个线程都会执行自身的初始化步骤。A1更适合用归约替代原子操作:原子操作虽能避免竞争,但每次更新都需同步,会带来显著性能开销。观察循环结构,A1(iY,iBp,iKp)的更新由不同iYp循环项累加而来,若将外层iKp、iBp、iY循环作为并行层级,为A1指定数组归约(REDUCTION(+:A1))会更高效(主流新编译器均支持数组归约)。或者调整并行循环层级,让每个线程负责独立的(iY,iBp,iKp)块,线程仅更新自身负责的A1元素,完全规避竞争,无需原子操作或归约。
- 对应(ikp,ibp,iy,iyp)的线程会访问哪个tempibk数组?
每个线程都有独立的tempibk私有副本。由于你在!$OMP PARALLEL DO中声明tempibk为PRIVATE,OpenMP会为每个线程分配单独的内存空间存储tempibk。无论当前处理的是哪个(iKp,iBp,iY,iYp)组合,线程仅访问自身私有的tempibk数组,不会与其他线程的tempibk产生冲突。
内容的提问来源于stack exchange,提问作者Zillux
相关产品推荐
相关产品推荐

