Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Fortran OpenMP及其子例程和函数_Fortran_Thread Safety_Openmp - Fatal编程技术网

Fortran OpenMP及其子例程和函数

Fortran OpenMP及其子例程和函数,fortran,thread-safety,openmp,Fortran,Thread Safety,Openmp,免责声明:我很确定这已经在某个地方得到了回答,但我和另一个人一直在努力搜索,但没有结果 我有一个类似这样的代码: PROGRAM main !$omp parallel do !$omp private(somestuff) shared(otherstuff) DO i=1,n ... CALL mysubroutine(args) ... a=myfunction(moreargs) ..

免责声明:我很确定这已经在某个地方得到了回答,但我和另一个人一直在努力搜索,但没有结果

我有一个类似这样的代码:

      PROGRAM main
!$omp parallel do
!$omp private(somestuff) shared(otherstuff)
      DO i=1,n
        ...
        CALL mysubroutine(args)
        ...
        a=myfunction(moreargs)
        ...
      ENDDO
!$omp end parallel do
      END PROGRAM
      SUBROUTINE mysubroutine(things)
      ...
      END SUBROUTINE
      FUNCTION myfunction(morethings)
      ...
      END FUNCTION

我无法确定在何处/如何处理子程序和函数中变量的private、shared、reduce等子句。我怀疑答案可能有一些细微差别,因为有很多很多方法可以声明变量并在它们之间共享。那么,让我们假设主程序所涉及的所有变量都在它或共享模块中定义,并且对这些变量的任何OMP操作都可以在主代码中处理。子例程和函数使用其中的一些变量,并且有一些自己的变量。因此,我认为问题归结为如何处理局部变量的子句

好的,这是关于OpenMP指令的词法和动态范围以及与变量作用域的交互之间的差异。指令的词法范围是在指令之后的结构化块的开始和结束之间的文本。动态范围是词法范围加上作为任何子程序的一部分执行的语句,这些子程序是词法范围中的语句的结果。所以在类似

Program stuff
   Implicit None
   Real, Dimension( 1:100 ) :: a
   Call Random_number( a )
   !$omp parallel default( none ) shared( a )
   Call sub( a )
   !$omp end parallel
Contains
   Subroutine sub( a )
      Real, Dimension( : ), Intent( InOut ) :: a
      Integer :: i
      !$omp do
      Do i = 1, Size( a )
         a( i ) = 2.0 * a( i )
      End Do
   End Subroutine Sub
End Program stuff
(完全未经测试,直接写在这里)平行区域的词汇范围由$omp并行只是

   Call sub( a )
而动态范围是子例程的调用和内容。以及术语的完整性$omp do是孤立指令的一个示例,该指令不在另一个指令的词法范围内,而是在动态范围内。看

再比如说

为什么这很重要?您只能显式地为词法范围中的实体定义变量,在本例中仅为数组a,但对于由于执行动态范围而定义的实体,您不能这样做!相反,OpenMP有许多规则,简单来说就是

  • 子程序参数的作用域是从调用点继承的,即,如果在词法范围开始时将它们的作用域设置为私有,则它们保持私有,如果共享,则它们保持共享
  • 子程序的局部变量在默认情况下是私有的(因此上面的i是私有的,正如您所希望的),除非它们是用SAVE属性声明的(显式或隐式),在这种情况下它们是共享的
  • 根据我的经验,这会让你受益匪浅!结合使用动态范围和孤立指令是控制OpenMP程序的一个好方法,我不得不说我不同意上面的评论,我发现孤立工作共享指令确实非常有用!因此,您可以将上述所有功能结合起来,以执行以下操作

    Program dot_test
      Implicit None
      Real, Dimension( 1:100 ) :: a, b
      Real :: r
      a = 1.0
      b = 2.0
      !$omp parallel default( none ) shared( a, b, r )
      Call dot( a, b, r )
      Write( *, * ) r
      !$omp end parallel
    Contains
      Subroutine dot( a, b, r )
        Real, Dimension( : ), Intent( In    ) :: a, b
        Real,                 Intent(   Out ) :: r
        Real, Save :: s
        Integer :: i
        !$omp single
        s = 0.0
        !$omp end single
        !$omp do reduction( +:s )
        Do i = 1, Size( a )
           s = s + a( i ) * b( i )
        End Do
        !$omp end do
        !$omp single
        r = s
        !$omp end single
      End Subroutine dot
    End Program dot_test
    Wot now? gfortran -std=f95 -fopenmp -O -Wall -Wextra dot.f90 
    Wot now? export OMP_NUM_THREADS=3
    Wot now? ./a.out
       200.000000    
       200.000000    
       200.000000  
    
    这个简单的情况由于模块变量和公共块而有点复杂,所以不要使用全局变量。。。但如果必须这样做,则默认情况下它们是共享的,除非声明为threadprivate。看


    例如。

    显示此类函数的示例。如果局部变量不是
    save
    ,它们就不是问题。请看,你要研究的关键字是线程安全和线程安全过程。@VladimirF澄清一下,我有其他两个的代码,因此这更多的是语法问题,而不是线程安全问题<代码>保存是混合的,子例程和函数都会被大量调用,因此避免不必要的重复内存分配非常重要。尽管如此,如果使用
    SAVE
    将它们推到堆上(并损害性能),那么这是不值得的。测试可能正常。我不理解你的评论。你的全部问题都是关于线程安全的,不是吗?你想用什么样的语法?无法访问不在范围内的变量。如果你有代码,显示它!否则,您的问题太宽泛了。从您的评论来看,我不确定,但如果您在从OpenMP并行区域调用的过程中使用
    SAVE
    声明变量,则线程之间可能存在冲突。您可以在这些子例程中使用OpenMP指令:这种用法的术语是“孤立的”。很好的例子,我错了。对显示的
    save
    变量的处理也很有用。在Chandra的OpenMP并行编程中,有一个很好的关于孤立指令的讨论。