分割错误:11

当我尝试通过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),它返回分段错误:11。 当我有不同的NUM_THREADS时,返回Segmentation Fault:11时的变量i不同。

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

我也尝试在帮助子程序和主子程序中分配/取消分配,并且只在帮助子程序中分配/取消分配。 没有什么改变。


最典型的原因是堆栈中没有足够的空间来容纳numstrain的私有副本。 计算并比较以下两个值:

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

    请注意,无论您是否启用在堆上分配大型阵列的编译器选项(通过GNU的gfortran和英特尔的ifort进行测试),大多数Fortran OpenMP实现始终将专用阵列放置在堆栈上。

    如果注释掉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该模块 - 两种情况都会提供显式接口。 如果您没有提供显式接口,编译器将无法正确传递数组,并且子例程将无法访问其内容。

    链接地址: http://www.djcxy.com/p/79213.html

    上一篇: Segmentation fault: 11

    下一篇: How to nest parallel loops in a sequential loop with OpenMP