我目前正在尝试使用OpenMP 4.0的任务结构,包括我的Fortran代码的 depend 语句。因此,我创建了以下示例,该示例应该通过任务填充数字1到M的矩阵的第一行,并且每当第一行中的元素准备就绪时,通过任务填充剩余的元素。这导致以下代码:
use JSON;
my $result = from_json($json);
if($result->{field})
{
# YOUR CODE
};
使用英特尔Fortran 15编译器进行编译,该编译器根据 depend 语句的文档知识。但是每次执行时打印到屏幕上的结果都不同。即使矩阵的初始零点也停留在某些位置。例如:
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
为什么任务之间的依赖关系不能正常工作,因为我希望每行中的值为1到8?
答案 0 :(得分:2)
声明
!$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
将是私有的,但也会在创建任务时继承该值。
这个事实同样适用于同一语句中的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