Parallel processing OpenMP线程执行和threadprivate变量出现问题

Parallel processing OpenMP线程执行和threadprivate变量出现问题,parallel-processing,fortran,openmp,fortran90,Parallel Processing,Fortran,Openmp,Fortran90,我已经使用了8个线程进行8个循环。我用“print”来了解并行代码是如何工作的。0线程产生问题!我已经在所附的图表(请检查下面所附的链接)中展示了并行的工作原理。我使用了threadprivate,但结果表明线程0无法获取任何私有threadsafe变量 我也尝试过模块,得到了同样的结果! 你知道为什么代码会这样吗?如果有任何帮助或建议,我将不胜感激。谢谢 !$OMP PARALLEL DO do nb=m3+1, m3a, 2 60 icall=nb 65 iad=idint(

我已经使用了8个线程进行8个循环。我用“print”来了解并行代码是如何工作的。0线程产生问题!我已经在所附的图表(请检查下面所附的链接)中展示了并行的工作原理。我使用了threadprivate,但结果表明线程0无法获取任何私有threadsafe变量

我也尝试过模块,得到了同样的结果! 你知道为什么代码会这样吗?如果有任何帮助或建议,我将不胜感激。谢谢

  !$OMP PARALLEL DO
  do nb=m3+1, m3a, 2
  60 icall=nb
  65 iad=idint(a(icall))    
  if(iad.eq.0) goto 100     
  call ford(a(iad),servo)      
  if(.not.dflag) goto 80  
  atemp=dble(nemc)
  nemc=iad
  a(icall)=a(iad+6)
  a(iad+6) = atemp
  dflag=.false.
  goto 65    
  80 icall=iad+6     
  goto 65
  100 continue
  end do
  !$OMP END PARALLEL DO

  subroutine FORD(i,j)
  dimension zl(3),zg(3)
  common /ellip/ b1,c1,f1,g1,h1,d1,
   .               b2,c2,f2,g2,h2,p2,q2,r2,d2
  common /root/ root1,root2
  !$OMP threadprivate (/ellip/,/root/)
  CALL CONDACT(genflg,lapflg)
  return
  end subroutine

  SUBROUTINE CONDACT(genflg,lapflg)
  common /ellip/ b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2
  !$OMP threadprivate (/ellip/)
  RETURN
  END

仅看前几行,您就遇到了重大问题

   do nb=m3+1, m3a, 2
这部分很好,每个线程都有一个正确初始化的
nb
的私有副本

60   icall=nb
这是一个问题
icall
是共享的,每个线程将把它的私有值
nb
写入共享线程。线程同时运行,并且顺序和计时是非确定的,因此不能提前知道每个线程中的
icall
的值

65   iad=idint(a(icall))    
现在,我们使用
icall
计算一个值以存储在共享变量
iad
中。有什么问题?如果另一个线程在此线程执行期间向其写入了内容,则
icall
的值可能与前一行中的值不同。
iad
的值正在被每个线程重击

     if(iad.eq.0) goto 100     
     call ford(a(iad),servo)
这些线路存在与上述相同的问题。
iad
的值可能与上面的值不同,这两行之间的值也可能不同,具体取决于其他线程的执行情况

     if(.not.dflag) goto 80 
此时变量
dflag
尚未初始化

要解决这些问题,您需要将
icall
iad
声明为private with

!$omp parallel do private(icall,iad)
在使用dflag之前,还应初始化它


这些最初的错误可能会导致您的大部分问题,但可能无法解决所有问题。您已经构建了非常复杂(难以维护)的线程交互,并且您的代码中充满了错误的做法(隐式变量,随意使用
goto
),这使得代码很难遵循。

如果没有未显示的声明,则do循环体中有许多共享变量(
icall
iad
等)。您需要解决这个问题。请重新考虑这样的编码。隐式键入、
common
块,甚至
goto
都是麻烦。正如其他地方所写的,全局变量对于并行执行来说是个坏主意,正如您所发现的,不管全局变量是模块变量还是公共块实体,都无关紧要。正如在我对你的问题的回答中指出,你可能应该使用派生数据类型并将其传递给他人。然而,我仍然有点不清楚,你的实际算法是什么。你的福特呼叫的结果是在伺服中还是在一个公共块中找到的?现在,甚至不清楚这是否是可并行化的。责骂+1在你的最后一段中——隐式批量、多线程、共享内存、公共块、gotos——它将以眼泪结束。我支持Mark.OpenMP和典型Fortran 77或66的评论,这不是一个令人愉快的组合。