我使用8个线程进行8次循环。我用过' print'看看并行代码是如何工作的。 0线程产生问题!我已在附图中显示(请查看下面附带的链接)并行工作原理。我使用过threadprivate但事实证明,线程0无法获得任何私有线程安全变量。
我也尝试过模块并得到相同的结果! 知道代码为何如此行事吗?我将不胜感激任何帮助或建议。谢谢!
!$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
答案 0 :(得分:3)
只看前几行你就遇到了重大问题。
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
声明为私有
!$omp parallel do private(icall,iad)
您还应该在使用之前初始化dflag
。
这些第一个错误可能是您问题的一大部分,但可能无法解决所有问题。您构建了非常复杂(难以维护)的线程交互,并且您的代码充满了不良实践(隐式变量,自由使用goto
),这使得此代码难以遵循。