Fortran 中 MPI_FINALIZE() 期间的分段错误

drj*_*rm3 1 fortran memory-management mpi segmentation-fault fortran90

我在调用MPI_FINALIZE()Fortran 90 程序时遇到分段错误。虽然代码相当广泛,但我将发布伪代码并查看它是否引发任何标志。我有一种预感(但还没有尝试过)它可能是由于未释放数组引起的?但是,我不确定 - 在 Fortran 90 中无法取消分配数组会导致调用 期间出现分段错误MPI_FINALIZE吗?

if(<rank 0>) then
  do iat = 1,natoms
    do il = 0, LMAX
      do im = -il,il
        <mpi_recv "rank_rdy"> ! find out which rank is ready for (at,l,m)
        <mpi_send "(iat,il,im)"> ! send (at,l,m) to the rank asking for it
      enddo
    enddo
  enddo
else ! other ranks send a 'ready' signal and recieve the (at,l,m) to optimize
  if(<rank 0 is not finished processing (at,l,m)'s>)
    <mpi_send "my_rank"> ! tell rank 0 that i am ready to receive
    <mpi_recv "(iat,il,im)"> ! recieve (at,l,m) from rank 0
    call optimize(iat,il,im) ! do work on (at,l,m)
  endif
endif

if(<rank 0>)
  <read temp files created by other ranks>
  <write temp files to one master file>
endif

print*, 'calling finalize'

call MPI_BARRIER(MPI_COMM_WORLD, ierr)
call MPI_FINALIZE()
Run Code Online (Sandbox Code Playgroud)

现在,在输出中,除了与此问题无关的其他信息外,我还得到以下信息:

 calling finalize
 calling finalize
 calling finalize
 calling finalize
 calling finalize
 calling finalize

=====================================================================================
=   BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
=   EXIT CODE: 11
=   CLEANING UP REMAINING PROCESSES
=   YOU CAN IGNORE THE BELOW CLEANUP MESSAGES
=====================================================================================
APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault (signal 11)
Run Code Online (Sandbox Code Playgroud)

即使我不打电话MPI_BARRIER,我也会遇到同样的问题,但我认为这可能会有所帮助。请注意,每个等级中都使用了数组,我不费心去取消分配,因为我在整个程序中使用它们,所以我不担心内存泄漏或任何事情。是否有可能由于MPI_FINALIZE()在没有释放内存的情况下被调用而发生此段错误?

我将自己更多地探索这个问题,但我想发布这个问题有几个原因:

  1. 想知道这是否是调用时的已知问题 MPI_FINALIZE()

  2. 想知道为什么在调用MPI_FINALIZE(). 在内部,是什么导致了这个段错误?

  3. 我在网上搜索了高低并没有发现关于这个问题的任何信息,所以对于后代来说,这可能是一个在网上回答的好问题。

编辑:我忘了提及这一点,但是在串行运行时我无法复制此问题。显然,我不做(at,l,m)串行的分配。唯一的过程只是简单地遍历所有组合并一一优化它们。但是,我没有取消分配我认为可能导致 MPI 问题的数组,而且我仍然没有遇到段错误。

Hri*_*iev 5

如果可用,应始终使用 Fortran 90 MPI 接口而不是旧的 FORTRAN 77 接口。那是你应该总是

USE mpi
Run Code Online (Sandbox Code Playgroud)

代替

INCLUDE 'mpif.h'
Run Code Online (Sandbox Code Playgroud)

两者之间的区别在于 Fortran 90 接口将所有 MPI 子例程放在一个模块中,因此正在生成显式接口。这允许编译器在调用中进行参数检查并在您省略参数时发出错误信号。

在 Fortran 的调用约定中,所有参数都按地址传递,而不管它们的类型。这允许编译器生成对函数和子例程的正确调用,而无需像在 C 中那样需要原型。但这也意味着可以自由地传递一个INTEGER参数,其中REAL预期的数组为可以传递比预期更少/更多的参数。有一些外部工具,通常以 C 工具的名称称为linterslint,可以解析整个源代码树,并可以查明此类错误以及编译器不关心的许多其他错误。一种为 Fortran 进行静态代码分析的工具是flint. Fortran 90 添加了接口以补偿 Fortran 的这种容易出错的特性。

Calling a Fortran subroutine with fewer arguments than expected can have many different ill effects depending on the architecture but in most cases will result in crash, especially if the omitted argument is an output one. The called function doesn't know that less arguments are being passed - it just looks where its address should be and takes whatever address it finds there. As ierr是一个输出参数,将发生在该地址的写操作。该地址很可能不会指向对应于映射内存的虚拟地址,并且操作系统会传递严重的分段错误。即使地址指向用户分配的内存中的某处,结果也可能是覆盖某些控制结构中的重要值。如果甚至没有发生,那么调用约定中被调用者会清理堆栈帧 - 在这种情况下,堆栈指针将被错误地递增,并且返回地址将与正确的地址完全不同,这几乎是肯定会导致跳转到不可执行(甚至非映射)内存并再次导致分段错误。