在并行环境

时间:2016-08-28 22:57:35

标签: fortran openmp fortran90 gfortran

我认为我的问题与here所描述的问题有关甚至相同。但我不明白实际发生了什么。

我正在使用带有gfortran编译器的openMP,我有以下任务要做:我在二维表面上有一个密度分布F(X, Y),x坐标X和y坐标Y。矩阵F的大小为Nx x Ny

我现在有一组坐标Xp(i)Yp(i),我需要在这些点上插入密度F。此问题是为了并行化。

!$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(i)
    do i=1, Nmax

        ! Some stuff to be done here

        Fint(i) = interp2d(Xp(i), Yp(i), X, Y, F, Nx, Ny)

        ! Some other stuff to be done here

    end do
!$OMP END PARALLEL DO

除了i之外,所有内容都是共享的。函数interp2d正在进行一些简单的线性插值。

一个线程可以正常工作但多线程失败。我将问题追溯到hunt - 从Numerical Recipes中获取的子程序,该程序由interp2d调用。 hunt - 子例程基本上计算索引ix,使X(ix) <= Xp(i) < X(ix+1)。这是获得插值的起点所必需的。

使用多线程时,它会偶尔发生,一个线程从ix获取正确的索引hunt,并且调用hunt的线程接下来获得完全相同的索引,即使Xp(i)甚至不接近那一点。

我可以使用CRITICAL环境阻止这种情况:

!$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(i)
    do i=1, Nmax

        ! Some stuff to be done here

  !$OMP CRITICAL
        Fint(i) = interp2d(Xp(i), Yp(i), X, Y, F, Nx, Ny)
  !$OMP END CRITICAL

        ! Some other stuff to be done here

    end do
!$OMP END PARALLEL DO

但这会降低效率。如果我使用例如三个线程,我的CRITICAL环境的平均负载为1.5。没有我的负载平均值为2.75,但结果错误,甚至有时会出现SIGSEGV运行时错误。

这到底发生了什么?在我看来,所有线程都在调用相同的hunt - 子例程,如果它们同时执行,则会发生冲突。这有意义吗?

我该如何防止这种情况?

1 个答案:

答案 0 :(得分:1)

在Fortran 90+中组合变量声明和初始化具有赋予变量SAVE属性的副作用。

integer :: i = 0

大致相当于:

integer, save :: i

if (first_invocation) then
  i = 0
end if

SAVE'变量在例程的多次调用之间保留其值,因此通常作为静态变量实现。根据管理OpenMP中隐式数据共享类的规则,除非在threadprivate指令中列出,否则这些变量将被共享。

OpenMP要求兼容编译器应该应用上述语义,即使基础语言是Fortran 77也是如此。