我目前正在尝试使用 OpenMP 4.0 的 task 结构,包括 Fortran 代码的 depend 语句。因此,我创建了以下示例,该示例应通过任务用数字 1 到 M 填充矩阵的第一行,并在每次第一行中的元素准备就绪时通过任务填充剩余元素。这会产生以下代码:
PROGRAM OMP_TEST
IMPLICIT NONE
INTEGER K,L
INTEGER M
PARAMETER (M = 8)
INTEGER A(M,M)
A(1:M, 1:M) = 0
!$omp parallel
!$omp single
DO L=1, M
!$omp task depend(out:A(1,L)) default(shared)
A(1,L) = L
!$omp end task
DO K = 2, M
!$omp task depend(in:A(1,L)) default(shared)
A(K,L) = A(1,L)
!$omp end task
END DO
END DO
!$omp taskwait
!$omp end single
!$omp end parallel
DO K =1 , M
WRITE(*,*) A(K,1:M)
END DO
END PROGRAM
使用 Intel Fortran 15 编译器进行编译,根据文档了解 depend 语句。但每次执行时打印到屏幕上的结果都是不同的。甚至矩阵的初始零也保留在某些位置。例如:
1 2 3 4 5 6
7 8
0 0 0 0 0 0
0 0
0 0 3 4 0 0
0 8
1 0 3 4 0 6
0 8
1 0 3 4 5 6
0 8
1 2 3 4 5 6
7 8
0 2 3 4 5 6
7 0
1 2 3 4 5 6
0 8
为什么任务之间的依赖关系没有像我预期的那样正常工作,使得每行中都有值 1 到 8?
最佳答案
声明
!$omp task depend(in:A(1,L)) default(shared)
A(K,L) = A(1,L)
!$omp end task
将 K
视为共享,但在该任务执行时,K
的值可能已在其他地方修改(事实上,这可能仅由于线程而发生)执行单个 - 循环 DO K = 2,M
)。您可以通过将 firstprivate
子句添加到 !$omp
构造中来解决此问题。此子句确保 K
是私有(private)的,但每当创建该任务时也会继承该值。
这一事实同样适用于 L
中的相同语句以及前面几行的任务。以下代码对我使用英特尔 Fortran 编译器版本 16.0 有效。
PROGRAM OMP_TEST
IMPLICIT NONE
INTEGER K,L
INTEGER M
PARAMETER (M = 8)
INTEGER A(M,M)
A(1:M, 1:M) = 0
!$omp parallel
!$omp single
DO L=1, M
!$omp task depend(out:A(1,L)) default(shared) firstprivate(L)
A(1,L) = L
!$omp end task
DO K = 2, M
!$omp task depend(in:A(1,L)) default(shared) firstprivate(K,L)
A(K,L) = A(1,L)
!$omp end task
END DO
END DO
!$omp taskwait
!$omp end single
!$omp end parallel
DO K =1 , M
WRITE(*,*) A(K,1:M)
END DO
END PROGRAM
更新
在研究了 Grisu 引用英特尔示例的评论后,我意识到 K
和 L
应该已经是 firstprivate
因为它们是DO
中的循环变量。但是,添加 default(shared)
似乎会改变这种行为。以下代码已明确声明共享变量并已删除 default
,该代码也适用于英特尔 Fortran 16.0。
PROGRAM OMP_TEST
IMPLICIT NONE
INTEGER K,L
INTEGER M
PARAMETER (M = 8)
INTEGER A(M,M)
A(1:M, 1:M) = 0
!$omp parallel
!$omp single
DO L=1, M
!$omp task depend(out:A(1,L)) shared(A)
A(1,L) = L
!$omp end task
DO K = 2, M
!$omp task depend(in:A(1,L)) shared(A)
A(K,L) = A(1,L)
!$omp end task
END DO
END DO
!$omp taskwait
!$omp end single
!$omp end parallel
DO K =1 , M
WRITE(*,*) A(K,1:M)
END DO
END PROGRAM
关于parallel-processing - OpenMP - Fortran 中的任务依赖性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38782836/