Memory fortran90 deallocate语句导致内存损坏

Memory fortran90 deallocate语句导致内存损坏,memory,fortran,mpi,Memory,Fortran,Mpi,我构建了一个使用MPI\u-PACK、MPI\u-SEND、MPI\u-RECV分发fortran派生类型的最小示例,还交换了它们的边界来测试MPI\u-SENDRECV派生类型 代码虽然很好,但是它显示了一些奇怪的行为,如果我在代码的中间放代码< > DealPosie语句,而代码在代码末尾使用 DealPosie< /Cult>语句,它会对内存损坏造成一些奇怪的行为。dellocate语句在main脚本的左侧标有(*) 代码的流程是 1) MPI\u PACK整个派生类型 2) 使用MPI\

我构建了一个使用
MPI\u-PACK
MPI\u-SEND
MPI\u-RECV
分发fortran派生类型的最小示例,还交换了它们的边界来测试
MPI\u-SENDRECV
派生类型

<>代码虽然很好,但是它显示了一些奇怪的行为,如果我在代码的中间放代码< > DealPosie语句,而代码在代码末尾使用<代码> DealPosie< /Cult>语句,它会对内存损坏造成一些奇怪的行为。
dellocate
语句在
main
脚本的左侧标有
(*)

代码的流程是

1)
MPI\u PACK
整个派生类型

2) 使用
MPI\u SEND
MPI\u RECV
MPI\u UNPACK
恢复派生类型进行分发 结构

3)
MPI\u PACK
分布式本地派生类型的边界

4) 使用MPI\U SENDRECV在相邻处理器之间交换边界

我使用了与我测试的代码完全相同的代码,因此它们可以使用类似的
mpif90 mod_data\u structure.f90 main.f90-o main编译得很好,并且问题完全可以重现。下面的结果是来自
mpirun-np2 main
的输出

module mod_data_structure
  implicit none

  type type_cell
    real(selected_real_kind(15,307)):: xc(2)
    real(selected_real_kind(15,307)):: values_c(8)
    integer                      :: flag_boundary
  end type type_cell

  type type_cell_list
    type(type_cell)              :: cell(13,13)
  end type type_cell_list

  type type_cell_list_local
    type(type_cell),allocatable  :: cell(:,:)
  end type type_cell_list_local

end module mod_data_structure

使用代码> Debug(缓冲区)在代码的中间,输出的一部分看起来如下,它按照我的意图工作。

  After MPI_SENDRECV
 my_id            0
 cols             6
  0  0  0  0  0  0
  0  0  0  0  0  0
  0  0 11 12 15 16
  0  0 21 22 25 26
  0  0 31 32 35 36
  0  0 41 42 45 46
  0  0 51 52 55 56
  0  0 61 62 65 66
  0  0 71 72 75 76
  0  0 81 82 85 86
  0  0 91 92 95 96
  0  0  0  0  0  0
  0  0  0  0  0  0

但如果在代码中间找到<代码> Debug(缓冲区),输出的相同部分看起来是这样。

  After MPI_SENDRECV
 my_id            0
 cols             6
  0  0  0  0  0  0
******  0  0  0  0
****** 11 12 15 16
****** 21 22 25 26
****** 31 32 35 36
****** 41 42 45 46
****** 51 52 55 56
****** 61 62 65 66
****** 71 72 75 76
****** 81 82 85 86
  0  0 91 92 95 96
  0  0  0  0  0  0
  0  0  0  0  0  0
如果我改变
write
格式来显示更多的整数位数,它们是10位数的整数,类似于
1079533568

我在上看到过这种问题,但是没有明确的答案来解释为什么把
deallocate
变量语句放在代码的中间,而我不会在代码的其余部分使用它


这个问题从何而来?

我不确定我是否公正地回答了这个问题,但我对派生类型的实际经验是,用不同的MPI实现处理它们最安全的方法是不使用任何高级MPI构造,并将所有派生类型都保留在Fortran端

例如,我会编写
pure
函数来打包和扩展数据类型:

integer, parameter :: TYPE_CELL_BUFSIZE = 11

pure function type_cell_pack(this) result(buffer)
   class(type_cell), intent(in) :: this
   real(real64) :: buffer(TYPE_CELL_BUFSIZE)

   buffer(1:8) = this%values_c
   buffer(9:10) = this%xc

   ! It will be faster to not use a separate MPI command for this only
   buffer(11) = real(this%flag_boundary,real64)

end function type_cell_pack

pure type(type_cell) function type_cell_unpack(buffer) result(this)
   real(real64), intent(in) :: buffer(TYPE_CELL_BUFSIZE)

   this%values_c = buffer(1:8)
   this%xc = buffer(9:10)
   this%flag_boundary = nint(buffer(11))

end function type_cell_unpack
然后仅使用MPI_send和MPI_recv为MPI通信编写两个包装器,对于标量量如下:

subroutine type_cell_send_scalar(this,fromCpu,toCpu,mpiWorld)
   type(type_cell), intent(inout) :: this
   integer, intent(in) :: fromCpu,toCpu,mpiWorld

   real(real64) :: mpibuf(TYPE_CELL_BUFSIZE)

   if (cpuid==fromCpu) then 
      mpibuf = type_cell_pack(this)
      call mpi_send(...,mpibuf,...,MPI_DOUBLE_PRECISION,...)
   elseif (cpuid==toCpu) then 
      call mpi_recv(...,mpibuf,...,MPI_DOUBLE_PRECISION,...)
      this = type_cell_unpack(mpibuf)
   endif

end subroutine type_cell_send_scalar
subroutine type_cell_send_array(these,fromCpu,toCpu,mpiWorld)
   type(type_cell), intent(inout) :: these(:)
   integer, intent(in) :: fromCpu,toCpu,mpiWorld

   integer :: i,ncell,bufsize
   real(real64) :: mpibuf(TYPE_CELL_BUFSIZE*size(these))

   ncell = size(these)
   bufsize = ncell*TYPE_CELL_BUFSIZE

   if (cpuid==fromCpu) then 
      do i=1,ncell
        mpibuf((i-1)*TYPE_CELL_BUFSIZE+1:i*TYPE_CELL_BUFSIZE) = type_cell_pack(these(i))
      end do

      call mpi_send(bufsize,mpibuf,...,MPI_DOUBLE_PRECISION,...)
   elseif (cpuid==toCpu) then 
      call mpi_recv(bufsize,mpibuf,...,MPI_DOUBLE_PRECISION,...)
      do i=1,ncell
        these(i) = type_cell_unpack(mpibuf((i-1)*TYPE_CELL_BUFSIZE+1:i*TYPE_CELL_BUFSIZE))
      end do
   endif

end subroutine type_cell_send_array
对于数组数量,请执行以下操作:

subroutine type_cell_send_scalar(this,fromCpu,toCpu,mpiWorld)
   type(type_cell), intent(inout) :: this
   integer, intent(in) :: fromCpu,toCpu,mpiWorld

   real(real64) :: mpibuf(TYPE_CELL_BUFSIZE)

   if (cpuid==fromCpu) then 
      mpibuf = type_cell_pack(this)
      call mpi_send(...,mpibuf,...,MPI_DOUBLE_PRECISION,...)
   elseif (cpuid==toCpu) then 
      call mpi_recv(...,mpibuf,...,MPI_DOUBLE_PRECISION,...)
      this = type_cell_unpack(mpibuf)
   endif

end subroutine type_cell_send_scalar
subroutine type_cell_send_array(these,fromCpu,toCpu,mpiWorld)
   type(type_cell), intent(inout) :: these(:)
   integer, intent(in) :: fromCpu,toCpu,mpiWorld

   integer :: i,ncell,bufsize
   real(real64) :: mpibuf(TYPE_CELL_BUFSIZE*size(these))

   ncell = size(these)
   bufsize = ncell*TYPE_CELL_BUFSIZE

   if (cpuid==fromCpu) then 
      do i=1,ncell
        mpibuf((i-1)*TYPE_CELL_BUFSIZE+1:i*TYPE_CELL_BUFSIZE) = type_cell_pack(these(i))
      end do

      call mpi_send(bufsize,mpibuf,...,MPI_DOUBLE_PRECISION,...)
   elseif (cpuid==toCpu) then 
      call mpi_recv(bufsize,mpibuf,...,MPI_DOUBLE_PRECISION,...)
      do i=1,ncell
        these(i) = type_cell_unpack(mpibuf((i-1)*TYPE_CELL_BUFSIZE+1:i*TYPE_CELL_BUFSIZE))
      end do
   endif

end subroutine type_cell_send_array

您的代码无法编译-(a,i,a)是无效的格式,您需要提供整数的宽度part@IanBush我使用的是ifort 19.0.5.281,使用这个编译器,代码可以很好地编译。我想编译器处理了无效的格式。谢谢你让我知道这是一个无效的格式!感谢您用如此详细的示例代码给出答案。它似乎对我的代码真正实现MPI例程有很大帮助。谢谢:)