因此,我有一个简单的Fortran do循环,在该循环内调用了两个子例程。我有使do循环与OpenMP并行,像这样]
!$omp parallel do do i=1,n call a() call b() enddo !$omp end parallel do
现在大多数情况下,循环中的迭代次数为与可用的处理器/线程数和内部调用的子例程相比要少循环可以并行调用。所以,有没有办法在并行内部并行调用子例程做循环?我已经尝试过像这样的
task
!$omp parallel do do i=1,n !$omp task call a(i , j ) !$omp end task !$omp task call b(i, k) !$omp end task !$omp taskwait enddo !$omp end parallel do
但是这显示了
segmentation fault
的某些错误。有什么方法可以实现这一目标。
因此,我发现分段错误的主要原因来自fftw库。让我们考虑一个虚拟程序
program name !$use omp_lib implicit real*8(a-h,p-z) call system_clock(count_rate=irate) call system_clock(it1) !$ call omp_set_nested(.true.) !$omp parallel do do i =1,5 call test(i) print *, i enddo !$omp end parallel do call system_clock(it2) print *, (it2-it1)/real(irate, kind=8) end program name subroutine test(ii) ! just a dummy subroutine for heavy computation implicit real*8(a-h,p-z) do j=1,40000 !$omp task do k=1,40000 x = exp(sqrt(sqrt(2.0d0*ii**3)**2)) enddo !$omp end task enddo end subroutine
该程序完全按照我的要求运行,并使用任务指令,使用剩余的线程并提高了性能。现在,让我们考虑另一个具有fftw的虚拟程序,类似于我正在使用的程序。
program name !$use omp_lib implicit real*8(a-h,p-z) integer, parameter :: n=8192*8 complex(kind=8) :: arr(n) real(kind=8) :: tmp1(n), tmp2(n) integer(kind=8) :: pF integer :: i call system_clock(count_rate=irate) call dfftw_plan_dft_1d(pF,n,arr,arr,-1,0) ! forward call system_clock(it1) !$ call omp_set_nested(.true.) !$omp parallel do private(arr) do i =1,5 call random_number(tmp1) call random_number(tmp2) arr = cmplx(tmp1, tmp2, kind=8) call test(pF, arr) print *, i enddo !$omp end parallel do call system_clock(it2) print *, (it2-it1)/real(irate, kind=8) end program name subroutine test(pF, arr) implicit real*8(a-h,p-z) complex(kind=8) :: arr(:) integer(kind=8) :: pF do j=1,100 !$omp task private(arr) do k=1, 100 call dfftw_execute_dft(pF, arr, arr) enddo !$omp end task enddo end subroutine
现在,这会引发分割错误。 (注意:我的实际程序中没有随机数字调用,它们只是出于虚拟目的)。我已经检查了http://www.fftw.org/fftw3_doc/Thread-safety.html和
fftw_execute
是线程安全的,并且该程序在没有task
指令的情况下仍可正常运行。但是使用task
会引发错误。有人知道如何解决此问题吗?
因此,我有一个简单的Fortran do循环,在该循环内调用了两个子例程。我已经使do循环与OpenMP并行,像这样!$ omp parallel do do i = 1,n ...
遗憾的是,为什么!$omp do parallel
是一个坏主意的又一个示例……我确实确实认为最好将线程创建阶段和工作共享阶段明确分开。