我正在尝试通过 OpenMP 并行化一个 fortran 循环。循环本质上只包含两个命令:
do i=1,LSample
calcSslice(Vpot(:,:,i), Sslice)
rpold = rp
combine_rp_matrices (rpold, Sslice, rp)
end do
calcSslice 子例程读取 Vpot(:,:,i),执行一些计算并将结果存储在矩阵 Sslice 中。combine_rp_matrices 使用 rpold 和 Sslice 来更新 rp。rp 充当运行变量,是程序的所需输出。来自不同迭代的 Sslice 矩阵与 rp 组合的顺序无关紧要。我第一次尝试并行化这个循环是这样的:
!$OMP PARALLEL DO DEFAULT(SHARED), PRIVATE(Sslice), SCHEDULE(DYNAMIC)
do i=1,LSample
calcSslice(Vpot(:,:,i), Sslice)
!$OMP CRITICAL
rpold = rp
combine_rp_matrices (rpold, Sslice, rp)
!$OMP END CRITICAL
end do
!$OMP END PARALLEL DO
这会编译并运行,但会产生错误的结果。使用以下代码,我得到正确的结果,但执行速度要慢得多(尽管仍然比序列化代码快):
!$OMP PARALLEL DO DEFAULT(SHARED), PRIVATE(Sslice), SCHEDULE(DYNAMIC)
do i=1,LSample
!$OMP CRITICAL(Crit2)
calcSslice(Vpot(:,:,i), Sslice)
!$OMP END CRITICAL(Crit2)
!$OMP CRITICAL
rpold = rp
combine_rp_matrices (rpold, Sslice, rp)
!$OMP END CRITICAL
end do
!$OMP END PARALLEL DO
因此,calcSslice 显然存在一些同步问题。但是,我不太明白这会发生在哪里。Vpot 只在 calcSslice 中读取而不写入,而 Sslice 是一个线程私有变量。calcSslice 中使用的任何全局变量也只能从中读取。变量 rpold 和 rp 在 DO 循环所属的子例程范围内声明,因此 calcSslice 无法访问。calcSslice 中声明的变量使用以下属性:intent(in)、intent(out)、target、pointer。
这哪里出错了?
编辑:问题已解决,原因是calcSslice
声明期间变量的初始化,这意味着save
属性。