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例程有很大帮助。谢谢:)