在编译选项中启用OpenMP时,我遇到一个非常奇怪的错误。我已将其固定为使用主程序子例程中的动态大小数组对模块子例程的调用。这是一个简化的示例:
module arr_mod
contains
subroutine add2_mod(arr)
integer, dimension(:) :: arr
integer i, n
n = size(arr)
do i=1,n
arr(i) = arr(i)+2
enddo
end subroutine
end module
PROGRAM TEST_OMP
use arr_mod
integer, dimension(2000000) :: array
array = 0
write(*,*) array(1)
contains
subroutine add2()
! Note that this subroutine is not even called in the main program...
! When the next line is commented, the program runs.
call add2_mod(array)
end subroutine
END PROGRAM TEST_OMP
当我在没有OpenMP的情况下编译并运行该程序时,它运行良好:
$ gfortran -o test_omp test_omp.f90
$ ./test_omp
0
但是当我使用OpenMP时,程序会立即出现段错误:
$ gfortran -o test_omp test_omp.f90 -fopenmp
$ ./test_omp
[1] 10291 segmentation fault ./test_omp
如果删除程序子例程(或简单地注释add2_mod
调用),即使使用OpenMP,它也可以正常工作。即使我直接从主程序调用add2_mod
子例程,它仍然可以正常工作。
[使用优化进行编译(使用-O3测试时,以及使用ulimit -s unlimited
设置无限堆栈时,也可以使用。
据我所知,它与Intel Fortran兼容(已在版本17上进行了测试,除了-qopenmp之外没有其他特定标志)。
-fopenmp表示-frecursive,即所有本地数组都将分配在堆栈上。将现有代码移植到OpenMP时,可能会导致令人惊讶的结果,尤其是如果堆栈大小导致分段错误有限制。
为了克服此限制,您可以使用allocatable
说明符将数组强制放在堆上:
module arr_mod
contains
subroutine add2_mod(arr)
integer, dimension(:) :: arr
integer i, n
n = size(arr)
do i=1,n
arr(i) = arr(i)+2
enddo
end subroutine
end module
PROGRAM TEST_OMP
use arr_mod
integer, dimension(:), allocatable :: array ! array is allocated on the heap
allocate(array(2000000))
array = 0
write(*,*) array(1)
contains
subroutine add2()
call add2_mod(array)
end subroutine
END PROGRAM TEST_OMP
哪个可以与-fopenmp
标志一起正常工作。