当我尝试通过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子例程中分配/解除分配。什么都没有改变。
答案 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
该模块 - 两种情况都可以提供显式接口。如果您不提供显式接口,则编译器将无法正确传递数组,并且子例程将无法访问其内容。