select 类型构造中的关联名称是否由 OpenMP 自动私有化?
Is the associated name in select type construct automatically privatized by OpenMP?
我正在尝试分配一个多态可分配数组 ary
,它可以采用 2 种扩展类型的 baseType
(extType1
及其扩展 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
但是,我后来尝试了第二个并行化版本 WITHOUT 将 this
声明为 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
与第一个并行化版本中声明为 POINTER
的 this
无关。因此,我删除了第一个版本中的 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
的相同元素。
我正在尝试分配一个多态可分配数组 ary
,它可以采用 2 种扩展类型的 baseType
(extType1
及其扩展 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
但是,我后来尝试了第二个并行化版本 WITHOUT 将 this
声明为 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
与第一个并行化版本中声明为 POINTER
的 this
无关。因此,我删除了第一个版本中的 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
的相同元素。