Asynchronous fortran openmp同步
我正在尝试通过OpenMP并行化fortran循环。循环本质上只包含两个命令: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作为一个运行变量,是程序所需
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