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

MPI多节点运行报错MPI_ERR_TRUNCATE:C语言并行代码求助

问题:MPI跨节点运行时出现MPI_ERR_TRUNCATE错误

我编写了一段用于多项式数组计算的C语言MPI代码,单节点运行16及以下任务时正常,但使用2节点共32个任务(每节点16个)运行时,出现如下错误:

[06:272259] *** An error occurred in MPI_Recv [06:272259] *** reported
by process [2965045249,0] [06:272259] *** on communicator
MPI_COMM_WORLD [06:272259] *** MPI_ERR_TRUNCATE: message truncated
[06:272259] *** MPI_ERRORS_ARE_FATAL (processes in this communicator
will now abort, [06:272259] *** and potentially your MPI job)
[07][[45243,1],31][btl_tcp.c:559:mca_btl_tcp_recv_blocking] recv(20)
failed: Connection reset by peer (104)

代码如下:

int main(int argc, char **argv)
{
  int id;
  int n;
  int i, size, arraySize;
  double *vet, valor, *vresp, resposta, tempo, a[GRAU + 1];
  int hostsize;
  char hostname[MPI_MAX_PROCESSOR_NAME];
  MPI_Status status;

  MPI_Init(&argc, &argv);
  MPI_Get_processor_name(hostname, &hostsize);
  MPI_Comm_rank(MPI_COMM_WORLD, &id);
  MPI_Comm_size(MPI_COMM_WORLD, &n);

  if (id == 0) // Master
  {
    MPI_Barrier(MPI_COMM_WORLD);

    MPI_Bcast(&a, GRAU, MPI_DOUBLE, 0, MPI_COMM_WORLD);

    for (size = TAM_INI; size <= TAM_MAX; size += TAM_INC)
    {
      tempo = -MPI_Wtime();
      for (int dest = 1; dest < n; ++dest)
      {
        int ini = 0;
        int fim = dest * size / (n - 1);
        int tam = fim - ini;

        MPI_Send(&ini, 1, MPI_INT, dest, 0, MPI_COMM_WORLD);
        MPI_Send(&tam, 1, MPI_INT, dest, 0, MPI_COMM_WORLD);
        MPI_Send(&x[ini], tam, MPI_DOUBLE, dest, 0, MPI_COMM_WORLD);
        ini = fim;
        fflush(stdout);
      }

      int total = 0;
      for (int dest = 1; dest < n; ++dest)
      {
        int ini_escravo;
        int tam_escravo;
        MPI_Recv(&ini_escravo, 1, MPI_INT, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, &status);
        MPI_Recv(&tam_escravo, 1, MPI_INT, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, &status);
        MPI_Recv(&y[ini_escravo], tam_escravo, MPI_DOUBLE, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, &status);
      }
      tempo += MPI_Wtime();
    }
  }
  else
  { // Slave
    MPI_Barrier(MPI_COMM_WORLD);

    MPI_Bcast(&a, GRAU, MPI_DOUBLE, 0, MPI_COMM_WORLD);

    for (arraySize = TAM_INI; arraySize <= TAM_MAX; arraySize += TAM_INC)
    {
      int ini, tam;
      MPI_Recv(&ini, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
      MPI_Recv(&tam, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
      MPI_Recv(&x[0], tam, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status);

      for (i = 0; i < tam; ++i)
        y[i] = polinomio(a, GRAU, x[i]);

      MPI_Send(&ini, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
      MPI_Send(&tam, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
      MPI_Send(&y[0], tam, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
      fflush(stdout);
    }
  }
  MPI_Finalize();
  return 0;
}
问题分析与解决方法

1. 数据划分逻辑错误

主节点发送数据的循环中,ini被定义为循环内的局部变量,每次循环都会重置为0,导致所有从节点收到的都是从索引0开始的重叠数据切片,且后续进程计算的tam可能远超出合理范围,引发内存越界和数据截断。

修复代码:将ini移到循环外,保证切片范围连续不重叠:

// 主节点发送循环修改为:
int ini = 0;
for (int dest = 1; dest < n; ++dest)
{
  int fim = dest * size / (n - 1);
  int tam = fim - ini;

  MPI_Send(&ini, 1, MPI_INT, dest, 0, MPI_COMM_WORLD);
  MPI_Send(&tam, 1, MPI_INT, dest, 0, MPI_COMM_WORLD);
  MPI_Send(&x[ini], tam, MPI_DOUBLE, dest, 0, MPI_COMM_WORLD);
  ini = fim;
  fflush(stdout);
}

2. MPI_Bcast元素数量不匹配

代码中a数组定义为double a[GRAU + 1](包含GRAU+1个系数),但MPI_Bcast只发送了GRAU个元素,导致最后一个多项式系数未传递,跨节点时内存布局差异会放大这个问题,引发不可预期的内存错误。

修复代码:调整Bcast的元素计数为GRAU + 1:

MPI_Bcast(&a, GRAU + 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);

3. 从节点缓冲区未初始化

从节点直接使用x[0]和y[0]但未分配内存,单节点时可能因栈空间侥幸正常,跨节点时会出现内存访问越界,导致接收数据截断或进程崩溃。

修复代码:从节点根据接收的tam动态分配缓冲区:

// 从节点循环内修改为:
int ini, tam;
MPI_Recv(&ini, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
MPI_Recv(&tam, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);

// 动态分配内存
double *x = malloc(tam * sizeof(double));
double *y = malloc(tam * sizeof(double));

MPI_Recv(x, tam, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status);

for (i = 0; i < tam; ++i)
  y[i] = polinomio(a, GRAU, x[i]);

MPI_Send(&ini, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
MPI_Send(&tam, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
MPI_Send(y, tam, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
fflush(stdout);

// 释放内存
free(x);
free(y);

同时需确保主节点的x、y数组已分配足够内存(至少size个元素)。

4. 接收消息的来源不匹配

主节点使用MPI_ANY_SOURCE接收时,三次MPI_Recv可能来自不同进程,导致ini_escravo、tam_escravo和结果数据不对应,引发数据错乱和截断错误。

修复代码:接收第一个消息后,固定后续消息的来源为同一进程:

// 主节点接收循环修改为:
for (int dest = 1; dest < n; ++dest)
{
  int ini_escravo;
  int tam_escravo;
  MPI_Recv(&ini_escravo, 1, MPI_INT, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, &status);
  int source = status.MPI_SOURCE; // 获取当前消息的发送进程
  MPI_Recv(&tam_escravo, 1, MPI_INT, source, 0, MPI_COMM_WORLD, &status);
  MPI_Recv(&y[ini_escravo], tam_escravo, MPI_DOUBLE, source, 0, MPI_COMM_WORLD, &status);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 06:35:32