从 OpenMP 4.5 开始,可以使用指令减少数组。但是,当我尝试在派生类型的数组上使用它时,我遇到了一个问题,因为找不到此类型的 !$OMP DECLARE REDUCTION。我理解这个问题。经过多次尝试,我终于找到了一个似乎有效的程序。这是代码:
模块(module.f90
):
module my_mod
implicit none
type :: my_type_t
integer :: x
integer :: y
end type my_type_t
interface operator(+)
module procedure add_my_type_t_vec
end interface
!$OMP DECLARE REDUCTION (+ : my_type_t : omp_out = omp_out + omp_in) INITIALIZER (omp_priv = omp_orig)
contains
function add_my_type_t_vec(a,b) result(res)
type(my_type_t), dimension(:),intent(in) :: a, b
type(my_type_t), dimension(size(a)) :: res
res(:)%x = a(:)%x + b(:)%x
res(:)%y = a(:)%y + b(:)%y
end function add_my_type_t_vec
end module my_mod
使用它的程序(pgm.f90
):
program parallel
use omp_lib
use my_mod
implicit none
type(my_type_t), dimension(:), allocatable :: private_var, shared_var
integer :: i
allocate(private_var(5), shared_var(5))
shared_var%x=0
shared_var%y=0
!$OMP PARALLEL NUM_THREADS(4) PRIVATE(private_var,i) REDUCTION (+ : shared_var)
!$OMP DO
do i=1,1000
private_var%x = 1
private_var%y = 2
shared_var = shared_var + private_var
end do
!$OMP END DO
!$OMP END PARALLEL
print *, "Total : ", shared_var
end program parallel
编译:gfortran -fopenmp module.f90 pgm.f90
为了找到此解决方案,我使用了以下答案https://stackoverflow.com/a/61148205/7462275。
它确实有效,但我不确定在某些情况下是否会出现未定义的行为。而且我不完全理解 DECLARE REDUCTION 和 INITIALIZER 指令的语法和机制。事实上,我复制/粘贴了上面提到的答案,但其中没有解释。感谢您的建议和解释。
问题是
INITIALIZER (omp_priv = omp_orig)
,只有当进入进行归约的区域之前归约变量为 0 时,它才有效。归约变量的私有实例应初始化为归约操作的中性元素。因为+
中性元素为 0。因为min
它将是“正无穷大”或任何最接近数据类型的表示。在这种特定情况下,我们需要一个具有正确大小的 0 个元素的数组,我们可以通过添加一个复制数组大小的初始化函数来实现:
现在,修改应用程序代码以使用不同的值输入缩减量即可显示差异:
使用原始初始化程序打印:
并使用修改后的初始化程序:
为了进一步了解如何使用归约,我建议查看 OpenMP 示例文档 (openmp.org/wp-content/uploads/openmp-examples-6.0.pdf) 以查找更多
udr
C 和 Fortran 示例。