OpenMP的专有阵列 - 分段故障:11(OpenMP private array - Segme

2019-07-04 02:56发布

当我尝试通过的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)的内存访问冲突发生。 我已经宣布我和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),则返回段错误:11。 变量,当它返回我分割故障:11是不同的,当我有不同的NUM_THREADS。

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

我也试图在帮助子程序和主子程序都分配/解除分配,只有在帮助子程序分配/解除分配。 没有被改变。

Answer 1:

造成这种情况的最典型的原因是没有足够的可用空间堆栈持有的私有副本上numstrain 。 计算和比较以下两个值:

  • 以字节为单位的阵列的大小
  • 堆栈大小限制

有两种类型的堆栈大小限制。 主线程的堆栈大小由之类的东西在Unix系统过程限制控制(使用ulimit -s检查和修改此限制)或固定在链接时在Windows(重新编译或可执行的二进制编辑是必需的,以便更改此限制)。 附加的OpenMP线程的堆栈大小由像标准环境变量控制OMP_STACKSIZE ,或实现特定的GOMP_STACKSIZE (GNU / GCC OpenMP的)和KMP_STACKSIZE (英特尔的OpenMP)。

请注意,大多数的Fortran OpenMP的实现始终把民营阵列堆栈上,不管你启用在堆中分配大的数组的编译器选项(使用GNU的测试gfortran和Intel的ifort )。

如果您注释掉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该模块-这两种情况下将提供显式接口。 如果你不提供明确的接口,编译器会无法正确传递数组和子程序将无法访问其内容。



文章来源: OpenMP private array - Segmentation fault: 11