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

MPI中C语言收发字符串触发Segmentation Fault问题求助

MPI字符串发送段错误问题排查与修复

问题描述

需要实现从rank 0进程向最后一个rank进程发送字符串的功能,已安装所有MPI依赖,但运行程序时持续出现Segmentation Fault,推测内存分配存在问题。

原始代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>

int main(int argc, char **argv)
{
    int rank, size;
    char *hello_world = NULL;
    int hello_world_size = (strlen("Hello world :)") + 1) * sizeof(char);
    hello_world = malloc(hello_world_size);
    if (hello_world == NULL) exit(EXIT_FAILURE);

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    if(rank == 0)
    {
        strcpy(hello_world, "Hello world :)");

        MPI_Send(
            &hello_world,
            hello_world_size,
            MPI_CHAR,
            size - 1,
            0,
            MPI_COMM_WORLD
        );
    }

    if(rank == size - 1)
    {
        MPI_Recv(
            &hello_world,
            hello_world_size,
            MPI_CHAR,
            0,
            0,
            MPI_COMM_WORLD,
            MPI_STATUS_IGNORE
        );

        printf("%s from rank %i", hello_world, rank);
    }

    free(hello_world);
    hello_world = NULL;

    MPI_Finalize();
    exit(EXIT_SUCCESS);
}

编译与执行命令

  • 编译:mpicc -std=c11 -o hello_world -g -Wall -Wpedantic hello_world.c
  • 执行:mpirun --use-hwthread-cpus -np 4 ./hello_world 或 mpirun -np 2 ./hello_world

错误输出

Authorization required, but no authorization protocol specified

Authorization required, but no authorization protocol specified

[debian:55189] *** Process received signal ***
[debian:55189] Signal: Segmentation fault (11)
[debian:55189] Signal code: Address not mapped (1)
[debian:55189] Failing at address: 0x562a3c5652a0
[debian:55189] [ 0] /lib/x86_64-linux-gnu/libc.so.6(+0x3bfd0)[0x7fe32c154fd0]
[debian:55189] [ 1] /lib/x86_64-linux-gnu/libc.so.6(+0x155d59)[0x7fe32c26ed59]
[debian:55189] [ 2] /lib/x86_64-linux-gnu/libc.so.6(+0x5e168)[0x7fe32c177168]
[debian:55189] [ 3] /lib/x86_64-linux-gnu/libc.so.6(_IO_printf+0xab)[0x7fe32c16b56b]
[debian:55189] [ 4] ./hello_world(+0x12f8)[0x55d9fb4882f8]
[debian:55189] [ 5] /lib/x86_64-linux-gnu/libc.so.6(+0x271ca)[0x7fe32c1401ca]
[debian:55189] [ 6] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x85)[0x7fe32c140285]
[debian:55189] [ 7] ./hello_world(+0x1101)[0x55d9fb488101]
[debian:55189] *** End of error message ***
--------------------------------------------------------------------------
Primary job  terminated normally, but 1 process returned
a non-zero exit code. Per user-direction, the job has been aborted.
--------------------------------------------------------------------------
--------------------------------------------------------------------------
mpirun noticed that process rank 1 with PID 0 on node debian exited on signal 11 (Segmentation fault).

问题根源

段错误的核心原因是MPI_Send和MPI_Recv的缓冲区参数传递错误:

  • 代码中传递的是&hello_world(指针变量自身的地址),但MPI需要的是数据缓冲区的起始地址(即hello_world本身,因为它已经是指向堆内存的指针)。
  • 接收进程尝试将数据写入&hello_world时,实际修改了指针变量的内存地址,而非指针指向的堆内存,导致后续printf使用无效地址触发段错误。

次要问题:

  1. printf缺少换行符,可能导致输出缓冲无法及时刷新。
  2. 内存分配失败时直接exit,未通知其他MPI进程,可能引发异常。

修复后的代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>

int main(int argc, char **argv)
{
    int rank, size;
    char *hello_world = NULL;
    const char *msg = "Hello world :)";
    int hello_world_size = (strlen(msg) + 1) * sizeof(char);

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    // 所有进程统一分配内存,避免分支逻辑
    hello_world = malloc(hello_world_size);
    if (hello_world == NULL) {
        fprintf(stderr, "Rank %d: 内存分配失败\n", rank);
        MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
    }

    if(rank == 0)
    {
        strcpy(hello_world, msg);
        // 传递缓冲区起始地址hello_world,而非指针的地址
        MPI_Send(
            hello_world,
            hello_world_size,
            MPI_CHAR,
            size - 1,
            0,
            MPI_COMM_WORLD
        );
    }

    if(rank == size - 1)
    {
        // 同样传递hello_world作为缓冲区地址
        MPI_Recv(
            hello_world,
            hello_world_size,
            MPI_CHAR,
            0,
            0,
            MPI_COMM_WORLD,
            MPI_STATUS_IGNORE
        );
        // 添加换行符确保输出刷新
        printf("%s from rank %d\n", hello_world, rank);
    }

    free(hello_world);
    hello_world = NULL;

    MPI_Finalize();
    return EXIT_SUCCESS;
}

关键修复点

  • 修正MPI缓冲区参数:将&hello_world改为hello_world,让MPI直接操作指针指向的堆内存。
  • 统一内存分配逻辑:所有进程都分配内存,使用MPI_Abort处理分配失败,确保集群内所有进程同步退出。
  • 修复输出格式:添加换行符,解决输出缓冲导致的显示问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 19:07:35