MPI_Gatherv收集可变大小数组异常:结果不符且疑似内存越界求助
问题分析与解决
你的问题核心是MPI_Gatherv的位移数组displs设置错误,同时由此引发了内存越界的问题,我们一步步拆解:
错误原因详解
MPI_Gatherv中displs数组的每个元素,表示对应进程的数据在根进程recvbuf中的起始偏移量(以recvtype的个数为单位),而不是随意设置的数值。
你当前的displs设置为[1,3,6],会导致:
- 根进程(rank0)自己的1个元素被写入
rbuf[1],而rbuf[0]因为没有被MPI写入,保留了malloc分配后的未初始化值(显示为0); - rank1的3个元素被写入
rbuf[3]到rbuf[5],中间的rbuf[2]同样是未初始化的0; - 最严重的是,rank2需要写入6个元素,起始偏移是6,这意味着需要
rbuf至少有6+6=12个int的空间,但你只分配了10个,直接导致内存越界访问——这就是你看到元素跑到rbuf第11、12位的原因,这属于未定义行为,随时可能导致程序崩溃。
正确的displs应该是前面所有进程rcounts的累加值:
- rank0的起始偏移:0(前面没有进程)
- rank1的起始偏移:
rcounts[0] = 1(rank0占了1个位置) - rank2的起始偏移:
rcounts[0]+rcounts[1] = 1+3=4(rank0+rank1共占了4个位置)
修改后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <mpi.h> int main (int argc, char *argv[]) { MPI_Init(&argc, &argv); int world_size,*sendarray; int rank, *rbuf=NULL, count; int *displs=NULL,i,*rcounts=NULL; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &world_size); if(rank==0){ rbuf = malloc(10*sizeof(int)); displs = malloc(world_size*sizeof(int)); rcounts=malloc(world_size*sizeof(int)); rcounts[0]=1; rcounts[1]=3; rcounts[2]=6; // 修正displs的计算 displs[0] = 0; displs[1] = rcounts[0]; displs[2] = rcounts[0] + rcounts[1]; sendarray=malloc(1*sizeof(int)); for(int i=0;i<1;i++)sendarray[i]=1; count=1; } if(rank==1){ sendarray=malloc(3*sizeof(int)); for(int i=0;i<3;i++)sendarray[i]=2; count=3; } if(rank==2){ sendarray=malloc(6*sizeof(int)); for(int i=0;i<6;i++)sendarray[i]=3; count=6; } MPI_Barrier(MPI_COMM_WORLD); MPI_Gatherv(sendarray, count, MPI_INT, rbuf, rcounts, displs, MPI_INT, 0, MPI_COMM_WORLD); if(rank==0){ int SIZE=10; for(int i=0;i<SIZE;i++)printf("(%d) %d ",i, rbuf[i]); free(rbuf); free(displs); free(rcounts); free(sendarray); // 新增:释放根进程的sendarray,避免内存泄漏 } if(rank!=0)free(sendarray); MPI_Finalize(); }
额外注意事项
- 根进程的
sendarray之前没有被释放,我在代码中补充了free(sendarray),避免内存泄漏; - 如果你不确定displs的计算,可以通过循环自动累加生成,比如在rank0中:
这样即使进程数或rcounts变化,也能自动生成正确的位移值。displs[0] = 0; for(int i=1; i<world_size; i++){ displs[i] = displs[i-1] + rcounts[i-1]; }
修改后运行,就能得到你预期的输出:
(0) 1 (1) 2 (2) 2 (3) 2 (4) 3 (5) 3 (6) 3 (7) 3 (8) 3 (9) 3
内容的提问来源于stack exchange,提问作者MsTais
相关产品推荐
相关产品推荐

