为什么访问 threadprivate 变量会导致分段错误?
Why accessing a threadprivate variable causes segmentation fault?
我正在修改使用 openmp 库的现有 Fortran 代码。此代码的原始版本可以完美地并行运行。
我在多线程期间访问某个变量时出现分段错误运行(我通过在代码中设置标志来验证)。这个数组被定义为可分配的,然后作为 threadprivate 然后分配,而在原始版本中它不是可分配的并且它的大小是立即设置的。由于给我的工作计划,我修改了这部分。
这是重现错误的一段基本代码。有罪的变量是一个名为 "var".
的数组
program testparallel
use omp_lib
implicit none
integer :: thread_id, thread_num
integer :: i,N
integer,dimension(:),allocatable,save :: var
!$omp threadprivate(var)
N = 20
allocate(var(5))
!$omp parallel default(shared) private(thread_id)
thread_id = omp_get_thread_num()
thread_num = omp_get_num_threads()
write(*,*)'Parallel execution on ',thread_num, ' Threads'
!$omp do
do i=1,N
var = 0
write(*,*) thread_id,i
end do
!$omp end do
!$omp end parallel
end program testparallel
原来的代码大概就是这样构成的,我没有直接修改这部分。 var 在循环内初始化,并且根据输入,它的值稍后由其他例程使用。
这是我得到的错误回溯:
Parallel execution on 2 Threads
0 1
0 2
Parallel execution on 2 Threads
0 3
0 4
0 5
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
0 6
Backtrace for this error:
0 7
0 8
0 9
0 10
#0 0x7F0149194697
#1 0x7F0149194CDE
#2 0x7F014824E33F
#3 0x400FB2 in MAIN__._omp_fn.0 at testparallel.F90:?
#4 0x7F0148C693C4
#5 0x7F01485ECDD4
#6 0x7F0148315F6C
#7 0xFFFFFFFFFFFFFFFF
如果我不将 var 定义为可分配的而是直接定义其大小(如在原始代码中),则不会发生段错误。如果我在将其设置为 threadprivate 之前对其进行分配,则会出现编译错误。
如何避免此错误,同时保持 var 可分配(这是必要的)?
编辑:我更正了原始代码的描述。
您的问题来自于这样一个事实:虽然您的可分配数组 var
被声明为 threadprivate
,但它仅在代码的 non-parallel 部分分配。因此,一旦在并行部分,只有主线程可以安全地访问数组。
一个非常简单的解决方法是将数组分配(以及随后的 de-allocation)包含在 parallel
部分中,如下所示:
!$omp parallel
allocate(var(5))
!$omp end parallel
我正在修改使用 openmp 库的现有 Fortran 代码。此代码的原始版本可以完美地并行运行。
我在多线程期间访问某个变量时出现分段错误运行(我通过在代码中设置标志来验证)。这个数组被定义为可分配的,然后作为 threadprivate 然后分配,而在原始版本中它不是可分配的并且它的大小是立即设置的。由于给我的工作计划,我修改了这部分。
这是重现错误的一段基本代码。有罪的变量是一个名为 "var".
的数组program testparallel
use omp_lib
implicit none
integer :: thread_id, thread_num
integer :: i,N
integer,dimension(:),allocatable,save :: var
!$omp threadprivate(var)
N = 20
allocate(var(5))
!$omp parallel default(shared) private(thread_id)
thread_id = omp_get_thread_num()
thread_num = omp_get_num_threads()
write(*,*)'Parallel execution on ',thread_num, ' Threads'
!$omp do
do i=1,N
var = 0
write(*,*) thread_id,i
end do
!$omp end do
!$omp end parallel
end program testparallel
原来的代码大概就是这样构成的,我没有直接修改这部分。 var 在循环内初始化,并且根据输入,它的值稍后由其他例程使用。
这是我得到的错误回溯:
Parallel execution on 2 Threads
0 1
0 2
Parallel execution on 2 Threads
0 3
0 4
0 5
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
0 6
Backtrace for this error:
0 7
0 8
0 9
0 10
#0 0x7F0149194697
#1 0x7F0149194CDE
#2 0x7F014824E33F
#3 0x400FB2 in MAIN__._omp_fn.0 at testparallel.F90:?
#4 0x7F0148C693C4
#5 0x7F01485ECDD4
#6 0x7F0148315F6C
#7 0xFFFFFFFFFFFFFFFF
如果我不将 var 定义为可分配的而是直接定义其大小(如在原始代码中),则不会发生段错误。如果我在将其设置为 threadprivate 之前对其进行分配,则会出现编译错误。
如何避免此错误,同时保持 var 可分配(这是必要的)?
编辑:我更正了原始代码的描述。
您的问题来自于这样一个事实:虽然您的可分配数组 var
被声明为 threadprivate
,但它仅在代码的 non-parallel 部分分配。因此,一旦在并行部分,只有主线程可以安全地访问数组。
一个非常简单的解决方法是将数组分配(以及随后的 de-allocation)包含在 parallel
部分中,如下所示:
!$omp parallel
allocate(var(5))
!$omp end parallel