Asynchronous fortran openmp同步

Asynchronous fortran openmp同步,asynchronous,parallel-processing,fortran,openmp,Asynchronous,Parallel Processing,Fortran,Openmp,我正在尝试通过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_矩阵使用rpold和Sslice更新rp。rp作为一个运行变量,是程序所需

我正在尝试通过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_矩阵使用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
这会编译并运行,但会产生错误的结果。使用以下代码,我得到了正确的结果,但执行速度要慢得多(尽管仍然比序列化代码快):

因此,calcSslice显然存在一些同步问题。然而,我不太明白这会发生在哪里。Vpot仅在calcSslice中读取,不写入,而Sslice是一个threadprivate变量。calcSslice中使用的任何全局变量也只能从中读取。变量rpold和rp在DO循环所属的子例程范围内声明,因此calcSslice无法访问。calcSslice中声明的变量使用以下属性:intent(in)、intent(out)、target、pointer

这哪里出了问题


编辑:问题解决了,原因是在声明过程中初始化了
calcSslice
中的变量,这意味着
save
属性。

我猜
calcSslice
不是线程安全的。确保此子例程不访问只读以外的全局变量,并且不要使用
save
属性(如果在声明期间初始化变量,请注意隐式保存!)。 您可以使用Intel提供的线程检测器来查找代码中的竞争条件。如果您无法访问此类软件,我将从一个虚拟过程开始,然后逐步填充例程以查看它在哪里失败


另一件让我困惑的事情是循环体的最后两行。每个线程备份整个矩阵,然后添加其切片。收集所有切片(例如,通过
reduce
子句)然后将大切片合并一次不是更好吗?

谢谢您的回答。有些指针在声明期间被初始化为null()。我不知道这意味着
save
属性。我会改变它,看看它是否有用。
Combine\rp\u matrix
使用
Sslice
更新
rp
。我必须收集
Sslice
-变量,这些变量比
rp
矩阵大4倍。矩阵都非常大,不适合堆栈,这就是为什么我实际上使用了
NThreads
Sslice
变量数组,而不是将其声明为private。对于小矩阵,即使使用私有
Sslice
,我描述的问题仍然存在,这就是我在问题中没有提到它的原因。
NThreads
LSample
小得多,一个
LSample
Sslice
s数组将占用太多内存。请检查函数的重入,这可能不安全。
!$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