select 类型构造中的关联名称是否由 OpenMP 自动私有化?

Is the associated name in select type construct automatically privatized by OpenMP?

我正在尝试分配一个多态可分配数组 ary,它可以采用 2 种扩展类型的 baseTypeextType1 及其扩展 extType2):

module mo
!$ use OMP_LIB

implicit none

type baseType
end type baseType

type, extends(baseType) :: extType1
    real :: r1
end type extType1

type, extends(extType1) :: extType2
    real :: r2
end type extType2

type arrayWrapper
    class(extType1), allocatable :: w
end type arrayWrapper

contains

subroutine wrapExtType1(aExt1, a)!-----------------------------------------------------
type(extType1    ), dimension(:)  , allocatable, intent(in   ) :: aExt1                !
type(arrayWrapper), dimension(:)  , allocatable, intent(  out) :: a                    !
integer                                                        :: n, i                 !
                                                                                       !
n = size(aExt1)                                                                        !
if (allocated(a)) deallocate(a); allocate(a(n))                                        !
do i = 1, n, 1; allocate(a(i)%w, source=aExt1(i)); end do                              !
end subroutine wrapExtType1!-----------------------------------------------------------

subroutine wrapExtType2(aExt2, a)!-----------------------------------------------------
type(extType2    ), dimension(:)  , allocatable, intent(in   ) :: aExt2                !
type(arrayWrapper), dimension(:)  , allocatable, intent(  out) :: a                    !
integer                                                        :: n, i                 !
                                                                                       !
n = size(aExt2)                                                                        !
if (allocated(a)) deallocate(a); allocate(a(n))                                        !
do i = 1, n, 1; allocate(a(i)%w, source=aExt2(i)); end do                              !
end subroutine wrapExtType2!-----------------------------------------------------------

!-SEQUENTIAL VERSION :
subroutine aryPrintTypes(a)!-----------------------------------------------------------
type(arrayWrapper) , dimension(:), allocatable, intent(in   ) :: a                     !
integer                                                       :: n, i                  !
                                                                                       !
n = size(a)                                                                            !
do i = 1, n, 1; select type (this=>a(i)%w)                                             !
type is (extType1)                                                                     !
    write(*,*) "Thread #", OMP_GET_THREAD_NUM(), "i =", i, &                           !
               "type is extType1, r1 =", this%r1                                       !
type is (extType2)                                                                     !
    write(*,*) "Thread #", OMP_GET_THREAD_NUM(), "i =", i, &                           !
               "type is extType2, r2 =", this%r2                                       !
end select; end do                                                                     !
end subroutine aryPrintTypes!----------------------------------------------------------

end module mo

!=====================================MAIN_PROGRAM=====================================!

program PolyArray
!$ use OMP_LIB
use mo

implicit none

type(arrayWrapper), dimension(:), allocatable :: ary
type(extType1    ), dimension(:), allocatable :: aryExt1
type(extType2    ), dimension(:), allocatable :: aryExt2
integer                                       :: n, i

n   = 8
allocate (aryExt1(n))
allocate (aryExt2(n))

do i=1,n,1
aryExt1(i)%r1 = 1.*i
aryExt2(i)%r2 = 2.*i
end do

call wrapExtType1(aryExt1, ary)
call aryPrintTypes(ary)
write(*,*) " "
call wrapExtType2(aryExt2, ary)
call aryPrintTypes(ary)

end program PolyArray

为了并行化 aryPrintTypes 子例程,起初,我认为 select type 构造会有问题,因为 关联名称 this 是在 AFTER 进入 !$OMP PARALLEL DO 循环后创建的。因此我写了第一个并行版本如下:

!-FIRST PARALLELIZED VERSION :
subroutine aryPrintTypes(a)!-----------------------------------------------------------
type(arrayWrapper) , dimension(:), allocatable, intent(in   ) :: a                     !
class(extType1   )               , pointer                    :: this                  !
integer                                                       :: n, i                  !
                                                                                       !
n = size(a)                                                                            !
!$OMP PARALLEL DO SCHEDULE(STATIC) DEFAULT(SHARED) PRIVATE(i, this)                    !
do i = 1, n, 1; select type (this=>a(i)%w)                                             !
type is (extType1)                                                                     !
    write(*,*) "Thread #", OMP_GET_THREAD_NUM(), "i =", i, &                           !
               "type is extType1, r1 =", this%r1                                       !
type is (extType2)                                                                     !
    write(*,*) "Thread #", OMP_GET_THREAD_NUM(), "i =", i, &                           !
               "type is extType2, r2 =", this%r2                                       !
end select; end do                                                                     !
!$OMP END PARALLEL DO                                                                  !
end subroutine aryPrintTypes!----------------------------------------------------------

以上代码如我所料工作正常。使用 8 个线程的输出如下:

 Thread #           0 i =           1 type is extType1, r1 =   1.0000000000000000     
 Thread #           2 i =           3 type is extType1, r1 =   3.0000000000000000     
 Thread #           6 i =           7 type is extType1, r1 =   7.0000000000000000     
 Thread #           5 i =           6 type is extType1, r1 =   6.0000000000000000     
 Thread #           4 i =           5 type is extType1, r1 =   5.0000000000000000     
 Thread #           7 i =           8 type is extType1, r1 =   8.0000000000000000     
 Thread #           3 i =           4 type is extType1, r1 =   4.0000000000000000     
 Thread #           1 i =           2 type is extType1, r1 =   2.0000000000000000     

 Thread #           6 i =           7 type is extType2, r2 =   14.000000000000000     
 Thread #           2 i =           3 type is extType2, r2 =   6.0000000000000000     
 Thread #           0 i =           1 type is extType2, r2 =   2.0000000000000000     
 Thread #           5 i =           6 type is extType2, r2 =   12.000000000000000     
 Thread #           7 i =           8 type is extType2, r2 =   16.000000000000000     
 Thread #           1 i =           2 type is extType2, r2 =   4.0000000000000000     
 Thread #           3 i =           4 type is extType2, r2 =   8.0000000000000000     
 Thread #           4 i =           5 type is extType2, r2 =   10.000000000000000

但是,我后来尝试了第二个并行化版本 WITHOUTthis 声明为 POINTER 并且,令人惊讶的是,它也可以工作 并且给出与第一个版本相同的结果:

!-SECOND PARALLELIZED VERSION :
subroutine aryPrintTypes(a)!-----------------------------------------------------------
type(arrayWrapper) , dimension(:), allocatable, intent(in   ) :: a                     !
integer                                                       :: n, i                  !
                                                                                       !
n = size(a)                                                                            !
!$OMP PARALLEL DO SCHEDULE(STATIC) DEFAULT(PRIVATE) SHARED(a, n)                       !
do i = 1, n, 1; select type (this=>a(i)%w)                                             !
type is (extType1)                                                                     !
    write(*,*) "Thread #", OMP_GET_THREAD_NUM(), "i =", i, &                           !
               "type is extType1, r1 =", this%r1                                       !
type is (extType2)                                                                     !
    write(*,*) "Thread #", OMP_GET_THREAD_NUM(), "i =", i, &                           !
               "type is extType2, r2 =", this%r2                                       !
end select; end do                                                                     !
!$OMP END PARALLEL DO                                                                  !
end subroutine aryPrintTypes!----------------------------------------------------------

我在大型内部计算代码中实现了两个版本,第一个版本一如既往地工作正常,但第二个版本的关联名称 this 未被 DO 循环中的 select type 结构识别。

编译器信息:

GNU Fortran (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

编辑:

一条评论表明 select type 构造中的 this 与第一个并行化版本中声明为 POINTERthis 无关。因此,我删除了第一个版本中的 POINTER 声明,结果相同:

!-FIRST PARALLELIZED VERSION **(EDITED)**:
subroutine aryPrintTypes(a)!-----------------------------------------------------------
type(arrayWrapper) , dimension(:), allocatable, intent(in   ) :: a                     !
integer                                                       :: n, i                  !
                                                                                       !
n = size(a)                                                                            !
!$OMP PARALLEL DO SCHEDULE(STATIC) DEFAULT(SHARED) PRIVATE(i)                          !
do i = 1, n, 1; select type (this=>a(i)%w)                                             !
type is (extType1)                                                                     !
    write(*,*) "Thread #", OMP_GET_THREAD_NUM(), "i =", i, &                           !
               "type is extType1, r1 =", this%r1                                       !
type is (extType2)                                                                     !
    write(*,*) "Thread #", OMP_GET_THREAD_NUM(), "i =", i, &                           !
               "type is extType2, r2 =", this%r2                                       !
end select; end do                                                                     !
!$OMP END PARALLEL DO                                                                  !
end subroutine aryPrintTypes!----------------------------------------------------------

所以提出了新问题select type中的关联名称this是否构造自动私有化通过 OpenMP 无需声明为 PRIVATE ?

它不需要(也不能)声明为 PRIVATE。关联名称只是选择器在执行 SELECT TYPE(或 ASSOCIATE)语句时指定的事物的同义词。

OpenMP 5.0 规范在 s2.19.1.1 中指出:

An associate name preserves the association with the selector established at the ASSOCIATE or SELECT TYPE statement.

关联名称和选择器之间的关联特定于每个线程。

与名称关联的事物是私有的还是共享的取决于选择器的数据共享属性。

在示例代码中,选择器的基础对象 a 是共享的,但后续索引确保不同线程不会访问该共享 a 的相同元素。