OpenMP私有阵列 - 分段错误:11

时间:2012-11-26 03:30:49

标签: parallel-processing fortran openmp fortran90

当我尝试通过OpenMP在Fortran90中并行化我的程序时,出现了分段错误错误。

    !$OMP PARALLEL DO NUM_THREADS(4) &
    !$OMP PRIVATE(numstrain, i)
    do irep = 1, nrep
        do i=1, 10
            PRINT *, numstrain(i)
        end do
    end do
    !$OMP END PARALLEL DO

我发现如果我注释掉“PRINT *,numstrain(i)”或删除openmp标志,它可以正常工作。我认为这是因为当我并行访问numstrain(i)时发生内存访问冲突。我已经将i和numstrain声明为私有变量。有人可以告诉我为什么会这样吗?非常感谢。 :)

更新:

我修改了以前的版本,这个版本可以打印出正确的结果。

integer, allocatable :: numstrain(:)
integer :: allocate_status
integer :: n
!$OMP PARALLEL DO NUM_THREADS(4) &
!$OMP PRIVATE(numstrain, i)
n = 1000000
do irep = 1, nrep
    allocate (numstrain(n), stat = allocate_status)
    do i=1, 10
        PRINT *, numstrain(i)
    end do
    deallocate (numstrain, stat = allocate_status)
end do
!$OMP END PARALLEL DO

但是,如果我将numstrain访问移动到此子例程调用的另一个子例程(下面附带的代码),1。它总是在一个线程中处理。 2.在某一时刻(i = 4或5),它返回Segmentation Fault:11。返回Segmentation Fault时的变量i:当我有不同的NUM_THREADS时,11是不同的。

integer, allocatable :: numstrain(:)
integer :: allocate_status
integer :: n
!$OMP PARALLEL DO NUM_THREADS(4) &
!$OMP PRIVATE(numstrain, i)
n = 1000000
do irep = 1, nrep
    allocate (numstrain(n), stat = allocate_status)
    call anotherSubroutine(numstrain)
    deallocate (numstrain, stat = allocate_status)
end do
!$OMP END PARALLEL DO

subroutine anotherSubroutine(numstrain)
    integer, allocatable   :: numstrain(:)
    do i=1, 10
        PRINT *, numstrain(i)
    end do
end subroutine anotherSubroutine

我还尝试在help子例程和main子例程中分配/解除分配,并且只在help子例程中分配/解除分配。什么都没有改变。

1 个答案:

答案 0 :(得分:3)

最常见的原因是堆栈上没有足够的空间来保存numstrain的私有副本。计算并比较以下两个值:

  • 数组的大小(以字节为单位)
  • 堆栈大小限制

堆栈大小限制有两种。主线程的堆栈大小由Unix系统上的进程限制(使用ulimit -s检查和修改此限制)控制,或者在Windows上的链接时修复(可执行文件的重新编译或二进制编辑是必要的)为了改变限制)。其他OpenMP线程的堆栈大小由标准OMP_STACKSIZE或特定于实现的GOMP_STACKSIZE(GNU / GCC OpenMP)和KMP_STACKSIZE(Intel OpenMP)等环境变量控制。 / p>

请注意,大多数Fortran OpenMP实现总是将私有数组放在堆栈上,无论您是否启用在堆上分配大型数组的编译器选项(使用GNU的gfortran和Intel的ifort进行测试)。 / p>

如果您注释掉PRINT语句,则会有效删除对numstrain的引用,编译器可以自由地对其进行优化,例如它可能根本不能制作numstrain的私有副本,因此不会超出堆栈限制。


在您提供的其他信息可以得出结论之后,该堆栈大小不是罪魁祸首。处理private ALLOCATABLE数组时,您应该知道:

  • 未分配数组的私有副本仍未分配;
  • 已分配数组的私有副本使用相同的边界进行分配。

如果你不在并行区域之外使用numstrain,你可以在第一种情况下做你已经完成的事情,但做了一些修改:

integer, allocatable :: numstrain(:)
integer :: allocate_status
integer, parameter :: n = 1000000
interface
   subroutine anotherSubroutine(numstrain)
      integer, allocatable :: numstrain(:)
   end subroutine anotherSubroutine
end interface

!$OMP PARALLEL NUM_THREADS(4) PRIVATE(numstrain, allocate_status)
allocate (numstrain(n), stat = allocate_status)
!$OMP DO
do irep = 1, nrep
   call anotherSubroutine(numstrain)
end do
!$OMP END DO
deallocate (numstrain)
!$OMP END PARALLEL

如果您还在并行区域之外使用numstrain,那么分配和释放将在外面进行:

allocate (numstrain(n), stat = allocate_status)
!$OMP PARALLEL DO NUM_THREADS(4) PRIVATE(numstrain)
do irep = 1, nrep
   call anotherSubroutine(numstrain)
end do
!$OMP END PARALLEL DO
deallocate (numstrain)

您还应该知道,当您调用以ALLOCATABLE数组作为参数的例程时,您必须为该例程提供显式接口。您可以编写INTERFACE块,也可以将调用的例程放在模块中,然后USE该模块 - 两种情况都可以提供显式接口。如果您不提供显式接口,则编译器将无法正确传递数组,并且子例程将无法访问其内容。