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

使用堆内存时MPI_Accumulate段错误,栈内存正常?求技术解答

MPI RMA堆分配缓冲区段错误及结果不符问题

问题描述

在学习MPI RMA累积操作场景中,工作进程需将自身rank值累积到rank=0进程的数组中:

  • 收发缓冲区在栈上分配时程序正常运行
  • 使用new或MPI_Alloc_mem堆分配时触发段错误
  • 移除MPI_Barrier后无段错误,但rank=0进程的rcv_buf输出值始终为-1,与预期结果不符
  • 运行环境:OpenMPI 4.1 + gcc 12.3

原始代码

#include <cstdio>
#include <cstddef>
#include <mpi.h>

int main (int argc, char *argv[])
{
  int my_rank, size;
  int count = 5;

  int *snd_buf;
  int *rcv_buf;

  MPI_Init(&argc, &argv);

  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  MPI_Comm_size(MPI_COMM_WORLD, &size);

  int expected_value = 0.0;

  if (my_rank == 0)
  {
    for(int i=0; i<size; ++i)  expected_value += i;
  }

  MPI_Alloc_mem(count * sizeof(int), MPI_INFO_NULL, &rcv_buf);
  MPI_Alloc_mem(count * sizeof(int), MPI_INFO_NULL, &snd_buf);
  memset(rcv_buf, -1, count * sizeof(int));

  MPI_Win window;

  if (my_rank == 0)
  {
    MPI_Win_create(&rcv_buf, count * sizeof(int), 1, MPI_INFO_NULL, MPI_COMM_WORLD, &window);
  }
  else
  {
    MPI_Win_create(MPI_BOTTOM, 0, 1, MPI_INFO_NULL, MPI_COMM_WORLD, &window);
  }

  if (my_rank != 0)
  {
    for(int i=0; i<count; ++i) snd_buf[i] =  my_rank;

    MPI_Win_lock(MPI_LOCK_EXCLUSIVE, 0, 0, window);
    MPI_Accumulate(&snd_buf, count, MPI_INT, 0, 0, count, MPI_INT, MPI_SUM, window);
    MPI_Win_unlock(0, window);
  }

  MPI_Barrier(MPI_COMM_WORLD);

  if (my_rank == 0)
  {
    printf("\n Expected result for all locations: %d\n", expected_value);
    printf(" Location   Value\n");
    for(int i=0; i<count; ++i)
      printf(" %5d %9d\n", i, rcv_buf[i]);
    printf("\n");
  }

  MPI_Free_mem(rcv_buf);
  MPI_Free_mem(snd_buf);

  MPI_Win_free(&window);
  MPI_Finalize();

  printf(" PE [%2d] done\n", my_rank);
}

问题定位与修正

核心错误点

  1. MPI_Win_create参数错误:
    rank=0进程中,MPI_Win_create第一个参数需传入缓冲区起始地址,但代码错误传入&rcv_buf(指针变量自身的栈地址)。其他进程通过RMA访问该地址时,会越界访问栈内存,直接触发段错误。
    修正:将&rcv_buf改为rcv_buf。

  2. MPI_Accumulate发送缓冲区参数错误:
    MPI_Accumulate第一个参数需传入发送缓冲区起始地址,代码错误传入&snd_buf(指针变量的栈地址),导致发送无效数据,rank=0的rcv_buf始终为初始值-1。
    修正:将&snd_buf改为snd_buf。

  3. 变量初始化不规范:
    expected_value为int类型,用浮点数0.0初始化属于不规范写法,修正为整数0。

  4. 补充缺失头文件:
    使用memset需包含<cstring>头文件,否则可能出现未定义行为。

修正后的代码

#include <cstdio>
#include <cstddef>
#include <mpi.h>
#include <cstring>

int main (int argc, char *argv[])
{
  int my_rank, size;
  int count = 5;

  int *snd_buf;
  int *rcv_buf;

  MPI_Init(&argc, &argv);

  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  MPI_Comm_size(MPI_COMM_WORLD, &size);

  int expected_value = 0;

  if (my_rank == 0)
  {
    for(int i=0; i<size; ++i)  expected_value += i;
  }

  MPI_Alloc_mem(count * sizeof(int), MPI_INFO_NULL, &rcv_buf);
  MPI_Alloc_mem(count * sizeof(int), MPI_INFO_NULL, &snd_buf);
  memset(rcv_buf, -1, count * sizeof(int));

  MPI_Win window;

  if (my_rank == 0)
  {
    MPI_Win_create(rcv_buf, count * sizeof(int), sizeof(int), MPI_INFO_NULL, MPI_COMM_WORLD, &window);
  }
  else
  {
    MPI_Win_create(MPI_BOTTOM, 0, 1, MPI_INFO_NULL, MPI_COMM_WORLD, &window);
  }

  if (my_rank != 0)
  {
    for(int i=0; i<count; ++i) snd_buf[i] =  my_rank;

    MPI_Win_lock(MPI_LOCK_EXCLUSIVE, 0, 0, window);
    MPI_Accumulate(snd_buf, count, MPI_INT, 0, 0, count, MPI_INT, MPI_SUM, window);
    MPI_Win_unlock(0, window);
  }

  // 用MPI_Win_fence替代Barrier,更贴合RMA同步语义
  MPI_Win_fence(0, window);

  if (my_rank == 0)
  {
    printf("\n Expected result for all locations: %d\n", expected_value);
    printf(" Location   Value\n");
    for(int i=0; i<count; ++i)
      printf(" %5d %9d\n", i, rcv_buf[i]);
    printf("\n");
  }

  MPI_Free_mem(rcv_buf);
  MPI_Free_mem(snd_buf);

  MPI_Win_free(&window);
  MPI_Finalize();

  printf(" PE [%2d] done\n", my_rank);
}

额外优化说明

  • 将MPI_Win_create的位移单位(第三个参数)从1改为sizeof(int),符合MPI规范(位移单位为字节数,对应int类型步长)。
  • 推荐用MPI_Win_fence替代MPI_Barrier,它专门用于RMA操作同步,语义更清晰,确保所有RMA操作完成后再访问数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 06:50:18