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; }
修复说明
- 动态分配本地数组:替换固定大小的
loc_matrix为动态分配,适配任意数组大小。 - 使用MPI_Scatterv处理非均匀分发:解决数组大小无法被进程数整除的问题,确保所有元素都被处理。
- 修正局部求和逻辑:所有进程使用本地的
loc_matrix计算局部和,避免访问未分配的全局数组。 - 初始化统计变量:
local_max、local_min、count_max、count_min均初始化为0,避免垃圾值。 - 并行统计元素数量:每个进程先统计本地的结果,再通过
MPI_Reduce归并到root,提升并行效率(原代码仅root统计,未利用并行)。 - 修复条件判断错误:将
my_rank = 0改为my_rank == 0,并调整统计逻辑为并行模式。 - 内存释放:所有动态分配的内存都被正确释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者mantz
相关产品推荐
相关产品推荐

