Desde o OpenMP 4.5, arrays podem ser reduzidos usando pragmas. Mas, eu enfrentei um problema quando tentei usá-lo em arrays de tipo derivado porque !$OMP DECLARE REDUCTION não foi encontrado para este tipo. Eu entendo o problema. Depois de muitas tentativas, eu finalmente encontrei um programa que parece funcionar. Este é o código:
O módulo ( 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
E o programa ( pgm.f90
) que o utiliza:
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
Compilação com:gfortran -fopenmp module.f90 pgm.f90
Para encontrar essa solução, usei a seguinte resposta https://stackoverflow.com/a/61148205/7462275 .
Funciona, mas não tenho certeza de que não terei comportamento indefinido em certas circunstâncias. E não entendo completamente a sintaxe e o mecanismo dos pragmas DECLARE REDUCTION e INITIALIZER. De fato, fiz uma cópia/colagem da resposta mencionada acima e não há explicação nela. Obrigado pelos conselhos e explicações.
O problema
INITIALIZER (omp_priv = omp_orig)
é que só funciona se a variável de redução for 0 antes de entrar na região com a redução. A instância privada da variável de redução deve ser inicializada para o elemento neutro da operação de redução. Pois+
o elemento neutro é 0. Poismin
seria "infinito positivo" ou qualquer que seja a representação mais próxima para o tipo de dado.Neste caso específico, precisamos de um array de 0 elementos que tenha o tamanho certo, o que podemos obter adicionando uma função inicializadora que copia o tamanho do array:
Agora, modificando o código do aplicativo para inserir a redução com um valor diferente, vemos a diferença:
Imprime com o inicializador original:
e com o inicializador modificado:
Para mais informações sobre como usar reduções, sugiro consultar o documento de exemplos do OpenMP (openmp.org/wp-content/uploads/openmp-examples-6.0.pdf) para encontrar mais
udr
exemplos em C e Fortran.