You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MPI_Gatherv收集可变大小数组异常:结果不符且疑似内存越界求助

问题分析与解决

你的问题核心是MPI_Gatherv的位移数组displs设置错误,同时由此引发了内存越界的问题,我们一步步拆解:

错误原因详解

MPI_Gatherv中displs数组的每个元素,表示对应进程的数据在根进程recvbuf中的起始偏移量(以recvtype的个数为单位),而不是随意设置的数值。

你当前的displs设置为[1,3,6],会导致:

  1. 根进程(rank0)自己的1个元素被写入rbuf[1],而rbuf[0]因为没有被MPI写入,保留了malloc分配后的未初始化值(显示为0);
  2. rank1的3个元素被写入rbuf[3]到rbuf[5],中间的rbuf[2]同样是未初始化的0;
  3. 最严重的是,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中:
    displs[0] = 0;
    for(int i=1; i<world_size; i++){
        displs[i] = displs[i-1] + rcounts[i-1];
    }
    
    这样即使进程数或rcounts变化,也能自动生成正确的位移值。

修改后运行,就能得到你预期的输出:

(0) 1 (1) 2 (2) 2 (3) 2 (4) 3 (5) 3 (6) 3 (7) 3 (8) 3 (9) 3

内容的提问来源于stack exchange,提问作者MsTais

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:17:58