Parallel processing openMP嵌套do循环的并行化

Parallel processing openMP嵌套do循环的并行化,parallel-processing,fortran,openmp,nested-loops,fortran77,Parallel Processing,Fortran,Openmp,Nested Loops,Fortran77,我在openmp fortran 77代码中有一个嵌套的do循环,无法并行化(该代码在运行时会出现分段错误)。我在同一代码的不同子例程中有一个非常相似的嵌套do循环,它并行运行,没有任何问题。 以下是我遇到问题的嵌套do循环: do n=1,num_p C$OMP PARALLEL DO DEFAULT(SHARED), PRIVATE(l,i1,i2,j1,j2,k1,k2 C$OMP& ,i,j,k,i_t,j_t,i_ddf,j_ddf,ddf_dum)

我在openmp fortran 77代码中有一个嵌套的do循环,无法并行化(该代码在运行时会出现分段错误)。我在同一代码的不同子例程中有一个非常相似的嵌套do循环,它并行运行,没有任何问题。 以下是我遇到问题的嵌套do循环:

      do n=1,num_p
C$OMP  PARALLEL DO DEFAULT(SHARED), PRIVATE(l,i1,i2,j1,j2,k1,k2
C$OMP& ,i,j,k,i_t,j_t,i_ddf,j_ddf,ddf_dum)
        do l=1,n_l(n)
          call del_fn(l,n)
          i1=p_iw(l,n)
          i2=p_ie(l,n)
          j1=p_js(l,n)
          j2=p_jn(l,n)
          k1=p_kb(l,n)
          k2=p_kt(l,n)
          do i=i1,i2
            i_ddf=i-i1+1
            if(i .lt. 1) then
              i_t=nx+i
            elseif (i .gt. nx) then
              i_t=i-nx
            else
              i_t=i
            endif
            do j=j1,j2
                j_ddf=j-j1+1
              if(j .lt.1) then
                j_t=ny+j
              elseif(j .gt. ny) then
                j_t=j-ny
              else
                j_t=j
              endif
              do k=k1,k2
                ddf(l,n,i_ddf,j_ddf,k-k1+1) = ddf_dum(i_t,j_t,k)
              enddo
            enddo
          enddo
        enddo
C$OMP END PARALLEL DO
      enddo

我已将问题缩小到ddf_dum(I_t,j_t,k)。当这个术语被关闭时(假设我用0.d0替换它),代码运行正常

另一方面,我有一个非常类似的嵌套do循环,它并行运行,没有任何问题。下面是并行运行的嵌套do循环,没有问题。有人能帮我找出我遗漏了什么吗

      do n=1,1
C$OMP  PARALLEL DO DEFAULT(SHARED), PRIVATE(l,i1,i2,j1,j2,k1,k2
C$OMP& ,i,j,k,i_f,j_f,i_ddf,j_ddf)
        do l=1,n_l(n)
          i1=p_iw(l,n)
          i2=p_ie(l,n)
          j1=p_js(l,n)
          j2=p_jn(l,n)
          k1=p_kb(l,n)
          k2=p_kt(l,n)
          u_forcing(l,n)= (u_p(l,n)-up_tilde(l,n))/dt
          v_forcing(l,n)= (v_p(l,n)-vp_tilde(l,n))/dt
          w_forcing(l,n)= (w_p(l,n)-wp_tilde(l,n))/dt
          do i=i1,i2
            i_ddf=i-i1+1
            if(i .lt. 1) then
              i_f=nx+i
            elseif (i .gt. nx) then
              i_f=i-nx
            else
              i_f=i
            endif
            do j=j1,j2
              j_ddf=j-j1+1
              if(j .lt.1) then
                j_f=ny+j
              elseif(j .gt. ny) then
                j_f=j-ny
              else
                j_f=j
              endif
              do k=k1,k2
                forcing_x(i_f,j_f,k)=forcing_x(i_f,j_f,k)+u_forcing(l,n)
 &                            *ddf_n(l,n,i_ddf,j_ddf,k-k1+1)*dv_l(l,n)
                forcing_y(i_f,j_f,k)=forcing_y(i_f,j_f,k)+v_forcing(l,n)
 &                            *ddf_n(l,n,i_ddf,j_ddf,k-k1+1)*dv_l(l,n)
                forcing_z(i_f,j_f,k)=forcing_z(i_f,j_f,k)+w_forcing(l,n)
 &                            *ddf_n(l,n,i_ddf,j_ddf,k-k1+1)*dv_l(l,n)
              enddo
            enddo
          enddo
        enddo
C$OMP END PARALLEL DO
      enddo

正如您所指出的,您的问题是
ddf\u dum
。它应该是一个共享变量,而不是私有变量,因为它只从中读取,从不写入。您将获得segfault,因为您试图访问非主线程的所有线程上的未初始化内存


一个很好的经验法则是,你可以自己发现这个错误:所有在平行区域内的等号RHS上找到的变量都应该是
共享的

正如你所指出的,你的问题是
ddf\u dum
。它应该是一个共享变量,而不是私有变量,因为它只从中读取,从不写入。您将获得segfault,因为您试图访问非主线程的所有线程上的未初始化内存


一个很好的经验法则是,你可以自己发现这个错误:所有在平行区域内的等号RHS上找到的变量都应该是
共享的

从未初始化的变量读取从技术上讲不是问题,除非这些变量是未分配的。让大型数组在堆栈上而不是堆上结束,这是使它们成为私有的结果。我已经缩小了问题的范围。我相信它来自于并行调用函数del_fn(公共变量ddf_dum在函数del_fn中更新)。现在我分别调用函数del_fn来更新ddf_dum,然后运行大型嵌套do循环来更新ddf。如果del_fn不能并行运行,那么一切都会顺利进行。因此,问题变成了如何并行运行函数del_fn?步骤1:删除所有公共变量。它们是糟糕的编程形式,几乎不可能正确地并行化代码。将它们重写为普通变量,并将它们作为参数发送给函数。步骤2:每个迭代是否独立于其他迭代?如果没有看到
del_fn
,我们就无法回答这个问题。是否有一种方法可以将子例程保持在嵌套的do循环中,或者必须将其内联编写?我问这个问题的原因是,我已经按照您的建议删除了公共变量,目前我正在尝试将其内联编写。但是它很长,我担心调试会花费相当长的时间。如果我能将子例程
del_fn
保留在嵌套的do循环中,那就容易多了。从未初始化的变量中读取从技术上来说不是问题,除非这些变量是未分配的。让大型数组在堆栈上而不是堆上结束,这是使它们成为私有的结果。我已经缩小了问题的范围。我相信它来自于并行调用函数del_fn(公共变量ddf_dum在函数del_fn中更新)。现在我分别调用函数del_fn来更新ddf_dum,然后运行大型嵌套do循环来更新ddf。如果del_fn不能并行运行,那么一切都会顺利进行。因此,问题变成了如何并行运行函数del_fn?步骤1:删除所有公共变量。它们是糟糕的编程形式,几乎不可能正确地并行化代码。将它们重写为普通变量,并将它们作为参数发送给函数。步骤2:每个迭代是否独立于其他迭代?如果没有看到
del_fn
,我们就无法回答这个问题。是否有一种方法可以将子例程保持在嵌套的do循环中,或者必须将其内联编写?我问这个问题的原因是,我已经按照您的建议删除了公共变量,目前我正在尝试将其内联编写。但是它很长,我担心调试会花费相当长的时间。如果我能将子例程
del_fn
保留在嵌套的do循环中,那就容易多了。