在OpenMP区域内调用内部子例程

时间:2014-09-02 16:23:42

标签: fortran openmp subroutine

我有一个包含子程序的模块,该子程序包含另一个子程序。外部子程序有一个并行的OpenMP区域,我在其中调用内部子程序。代码编译并运行时没有任何错误,但结果不正确。

module my_module
contains
    subroutine a(...)
        *...some variables*
        !$OMP PARALLEL DO DEFAULT(PRIVATE) SHARED(...)
        *...do some work*
         call b(...)

        !$OMP END PARALLEL DO
    contains
        subroutine b(...)
            *...some variables*
            *...do some work*
        end subroutine b
   end subroutine a
end my module

如果我运行英特尔调试器idb,它会在subroutine b内向我显示一个SIGSEGV。现在,如果我手动替换subroutine b内的subroutine a而不是调用它,并保留OMP子句,它将不会抛出SIGSEGV错误,结果现在是正确的。

编辑:完整代码在此处:https://github.com/mikolchon/cfd/blob/master/cfd2/calcRHS.f90 它是一个包含子程序的模块,用于求解欧拉流体方程。如果我运行idb,它将提供以下内容:

<code>idb</code> message

EDIT2:刚设法写了一个重现此错误的小例子:

module some_module
    implicit none
contains 
    subroutine sub0()
        real :: a(5)
        integer :: i
        a(:) = 0
        !$OMP PARALLEL DO DEFAULT(PRIVATE) SHARED(a)
        do i = 1, 5
            call sub1()
        end do
        !$OMP END PARALLEL DO
        print*, a(:)
    contains
        subroutine sub1()
            a(i) = a(i) + 1
        end subroutine sub1
    end subroutine sub0
end module some_module

program main
    use some_module
    implicit none
    call sub0()
end program main

该程序应打印1.000000 1.000000 1.000000 1.000000 1.000000。以下是我尝试的不同编译标志:(编译器是ifort 14.0.2)

ifort name.f90 -check bounds -traceback -O0 - 在没有OpenMP的情况下正常工作

ifort name.f90 -openmp -check bounds -traceback -O0 - 使数组索引超出范围。

ifort name.f90 -openmp -check bounds -traceback - 将有效

基本上,当我使用-O0时会出现错误。但是,这并不意味着当我不使用-O0时不会出现错误(我说这是因为我的原始代码会给出错误的结果)。另外,如果我明确地传递索引i,那就是:

....
call sub1(i) 
....
contains
    subroutine sub1(i)
        integer i
....

然后使用-O0进行编译,它将再次运行。所以我怀疑OpenMP在将变量i继承到子子例程时遇到了麻烦。

1 个答案:

答案 0 :(得分:3)

我不确定OpenMP规范是否允许这样做。这个帖子https://software.intel.com/en-us/forums/topic/297424也有一些疑问。也许英特尔Fortran错误地实施了它,但是必须仔细阅读官方规范。

在你的情况下,我会通过将过程代码直接粘贴到循环中来避免对主机关联的需要。

另一种选择是将私有变量作为伪参数传递,如引用的线程中所建议的那样,这也避免了主机关联。

我不确定单独使用足够高的优化级别是否有帮助,需要内联可能不安全。

FWIW我也遇到了与Oracle Solaris Studio 12.4beta相同的错误。


根据IanH:

&#34;内部子例程中对i的引用位于区域中,但不在构造中。在并行do构造或私有副本之前引用的i是否是原始i在OpenMP 4.0及更早版本中被称为&#34;未指定&#34;&#34;

具体的相关部分是(OpenMP 4.0 2.14.3.3.14):

The corresponding original list item. Inside the construct, all references to the original
list item are replaced by references to the new list item. In the rest of the region, it is
unspecified whether references are to the new list item or the original list item.

这意味着应该避免这种用法。