在OpenMP并行区域调用Fortran子程序时指针p为何呈共享状态?
问题分析:OpenMP并行区域内子程序指针变量共享问题
代码示例
主程序代码
type(type1) :: A(:) !$omp parallel private(variable_a, variable_b, ...) !$omp do do i = 1, n, 1 call A(i) % sub(variable_a, variable_b, ...) end do !$omp end do !$omp end parallel
(注:原代码中!$do和$enddo应为!$omp do和!$omp end do,属于笔误)
子程序代码
subroutine sub(this, val_a, val_b, ...) class(type1), intent(inout) :: this type(anytype), intent(in) :: val_a type(anytype), intent(in) :: val_b ... ! type_2 is another type defined in another file type(type2), pointer :: p => null do i = 1, n, 1 allocate(p) p => null() end do return end subroutine sub
问题原因
指针p被多个线程共享的核心原因在于Fortran的save属性规则:
- 当子程序内的局部变量带有显式初始化(比如这里的
p => null)时,Fortran编译器会自动为该变量添加save属性,使其在子程序调用之间保持值的持久化。 - 在OpenMP并行环境中,带有
save属性的变量默认被视为共享变量,所有线程会访问同一个p的实例,导致指针操作出现线程安全问题。
解决方法
你有两种可行的修正方案:
方案1:移除初始化,改为子程序内显式赋值
去掉指针声明时的初始化,在子程序开头显式将p设为null(),这样变量不会被自动赋予save属性,每个线程调用子程序时会创建独立的p副本:
subroutine sub(this, val_a, val_b, ...) class(type1), intent(inout) :: this type(anytype), intent(in) :: val_a type(anytype), intent(in) :: val_b ... type(type2), pointer :: p p => null() ! 显式赋值,无save属性 do i = 1, n, 1 allocate(p) p => null() end do return end subroutine sub
方案2:显式声明变量为私有
在子程序内通过OpenMP指令显式将p声明为线程私有,强制每个线程拥有独立实例:
subroutine sub(this, val_a, val_b, ...) class(type1), intent(inout) :: this type(anytype), intent(in) :: val_a type(anytype), intent(in) :: val_b ... type(type2), pointer :: p => null !$omp threadprivate(p) ! 显式声明线程私有 do i = 1, n, 1 allocate(p) p => null() end do return end subroutine sub
(注:threadprivate需要变量具有save属性,这里刚好符合初始化带来的save属性,因此可以直接使用)
内容的提问来源于stack exchange,提问作者if_summer
相关产品推荐
相关产品推荐

