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

MPI并行程序运行触发Segmentation fault信号11问题求助

MPI并行程序段错误(Signal 11)问题排查与修复

核心错误分析

  • 野指针访问:仅rank=0的进程分配了pinakas数组,其他进程的pinakas是未初始化的指针。代码中非0进程尝试通过pinakas[i]访问内存,直接触发段错误。
  • MPI_Scatter参数错误:发送端应直接传递数组指针pinakas而非&pinakas,接收端应传递数组名loc_matrix而非&loc_matrix(数组名本身就是指针)。
  • 局部求和逻辑错误:非0进程应使用Scatter分发到本地的loc_matrix计算局部和,而非访问不存在的pinakas。
  • 变量未初始化:count_max和count_min未初始化为0,累加后结果为垃圾值。
  • 条件判断错误:最后一段的if (my_rank = 0)是赋值操作而非判断,导致所有进程都会执行这段代码,非0进程再次访问未分配的pinakas引发崩溃。
  • 固定大小数组溢出风险:loc_matrix被定义为固定大小100,若plithos/p超过100会导致数组越界。
  • 未处理数组大小无法被进程数整除的情况:当plithos % p != 0时,部分元素未被分发计算,结果不准确。

修复后的完整代码

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

int main(int argc, char** argv){
    int p, plithos, i, count_max, count_min;
    int *pinakas = NULL;
    int *loc_matrix = NULL;
    int loc_num;
    int my_rank;
    int root, local_sum = 0, sum = 0;
    float average;
    
    MPI_Status status;
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
    MPI_Comm_size(MPI_COMM_WORLD, &p);  
    
    // 仅root进程读取输入并分配全局数组
    if (my_rank == 0) {
        printf("请输入数组大小: ");
        scanf("%d", &plithos);
        pinakas = (int *)malloc(plithos * sizeof(int)); 
        for (i = 0; i < plithos; i++) {
            printf("请输入第%d个元素: ", i);
            scanf("%d", &pinakas[i]);
        }
    }

    // 广播数组大小到所有进程
    MPI_Bcast(&plithos, 1, MPI_INT, 0, MPI_COMM_WORLD);
    
    // 计算本地元素数量,处理无法整除的情况
    loc_num = plithos / p;
    int remainder = plithos % p;
    if (my_rank < remainder) {
        loc_num += 1;
    }
    // 动态分配本地数组,避免固定大小溢出
    loc_matrix = (int *)malloc(loc_num * sizeof(int));
    
    // 使用Scatterv处理非均匀分发(当数组大小无法被进程数整除时)
    int *sendcounts = NULL;
    int *displs = NULL;
    if (my_rank == 0) {
        sendcounts = (int *)malloc(p * sizeof(int));
        displs = (int *)malloc(p * sizeof(int));
        int offset = 0;
        for (i = 0; i < p; i++) {
            sendcounts[i] = plithos / p;
            if (i < remainder) {
                sendcounts[i] += 1;
            }
            displs[i] = offset;
            offset += sendcounts[i];
        }
    }
    MPI_Scatterv(pinakas, sendcounts, displs, MPI_INT, loc_matrix, loc_num, MPI_INT, 0, MPI_COMM_WORLD);
    
    // 所有进程计算本地和
    for (i = 0; i < loc_num; i++){
        local_sum += loc_matrix[i];
    }

    // 归并所有局部和到root进程
    MPI_Reduce(&local_sum, &sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
    
    // root计算平均值并广播
    if (my_rank == 0) {
        average = (double)sum / plithos;
        printf("平均值为: %f\n", average);
    }
    MPI_Bcast(&average, 1, MPI_FLOAT, 0, MPI_COMM_WORLD);
    
    // 每个进程统计本地大于/小于平均值的元素数量,再归并到root
    int local_max = 0, local_min = 0;
    for(i=0; i<loc_num; i++){
        if(loc_matrix[i] > average){
            local_max++;
        } else if(loc_matrix[i] < average){
            local_min++;
        }
    }
    
    // 归并统计结果
    MPI_Reduce(&local_max, &count_max, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
    MPI_Reduce(&local_min, &count_min, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
    
    // root输出最终结果
    if (my_rank == 0) {
        printf("大于平均值的元素数量: %d\n", count_max);
        printf("小于平均值的元素数量: %d\n", count_min);
        // 释放root进程的动态内存
        free(pinakas);
        free(sendcounts);
        free(displs);
    }
    
    // 释放所有进程的本地数组
    free(loc_matrix);
    MPI_Finalize();
    return 0;
}

修复说明

  1. 动态分配本地数组:替换固定大小的loc_matrix为动态分配,适配任意数组大小。
  2. 使用MPI_Scatterv处理非均匀分发:解决数组大小无法被进程数整除的问题,确保所有元素都被处理。
  3. 修正局部求和逻辑:所有进程使用本地的loc_matrix计算局部和,避免访问未分配的全局数组。
  4. 初始化统计变量:local_max、local_min、count_max、count_min均初始化为0,避免垃圾值。
  5. 并行统计元素数量:每个进程先统计本地的结果,再通过MPI_Reduce归并到root,提升并行效率(原代码仅root统计,未利用并行)。
  6. 修复条件判断错误:将my_rank = 0改为my_rank == 0,并调整统计逻辑为并行模式。
  7. 内存释放:所有动态分配的内存都被正确释放,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 02:05:18