MPI广播数组失败,触发glibc无效stdio句柄致命错误求助
问题分析与修正方案
核心错误原因
- 非0进程文件指针非法:仅rank=0进程打开了文件,其他进程的
file指针未初始化,执行fseek和fscanf会访问无效内存,触发glibc的stdio句柄错误。 - 文件读取逻辑错误:所有进程都执行了文件读取操作,但只有rank=0能访问文件,其他进程无权限且无有效文件句柄。
- 行数统计不准确:原代码仅统计换行符数量,若文件最后一行无换行符,会少算一行。
- 异常处理不完整:rank=0文件打开失败时直接return,未通知其他进程终止,导致死锁。
修正后的代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <mpi.h> int fuelCalc(int array[], int elementCount, int myrank, int worldsize){ int fuelSum = 0; int addlFuelReq = 0; printf("Rank %d has array[0] value %d\n", myrank, array[0]); for(int i = 0; i < elementCount; i++){ if( (i % worldsize) == myrank){ usleep(1000000); addlFuelReq = (array[i]/4) - 3; if(addlFuelReq < 1){addlFuelReq = 1;} fuelSum += addlFuelReq; } } return fuelSum; } int main(){ int i = 0, N = 0; char fuelFile[30]; int totalFuel; int myrank, worldsize; FILE *file = NULL; int mysum; int *M = NULL; MPI_Init(NULL, NULL); MPI_Comm_rank(MPI_COMM_WORLD, &myrank); MPI_Comm_size(MPI_COMM_WORLD, &worldsize); if(myrank == 0){ printf("What file should be used?\n"); scanf("%s", fuelFile); file = fopen(fuelFile, "r"); if(file == NULL){ printf("The file entered does not exist.\n"); // 通知其他进程退出 N = -1; MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD); MPI_Finalize(); return 0; } // 修正行数统计:通过读取整数计数,兼容最后一行无换行的情况 N = 0; while(fscanf(file, "%d", &i) == 1){ N++; } printf("# of Lines: %d\n", N); // 回到文件开头 fseek(file, 0, SEEK_SET); // 动态分配数组,替代变长数组提升兼容性 M = (int*)malloc(N * sizeof(int)); if(M == NULL){ printf("Memory allocation failed.\n"); N = -1; MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD); fclose(file); MPI_Finalize(); return 0; } // 读取文件内容到数组 for(i=0; i<N; i++){ fscanf(file, "%d", &M[i]); } printf("M[0] = %d\n", M[0]); printf("Successfully scanned file in to M\n"); fclose(file); // 关闭文件避免资源泄漏 } // 广播行数N,非0进程接收 MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD); // 检查异常退出信号 if(N == -1){ MPI_Finalize(); return 0; } printf("rank %d has N value %d\n", myrank, N); // 非0进程分配数组内存 if(myrank != 0){ M = (int*)malloc(N * sizeof(int)); if(M == NULL){ printf("Rank %d: Memory allocation failed.\n", myrank); MPI_Finalize(); return 0; } } // 广播数组M MPI_Bcast(M, N, MPI_INT, 0, MPI_COMM_WORLD); printf("Rank %d has M[0] of %d\n", myrank, M[0]); mysum = fuelCalc(M, N, myrank, worldsize); if(myrank==0){printf("Successfully sent M, N, myrank, worldsize to other nodes\n");} MPI_Reduce(&mysum, &totalFuel,1,MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); if(myrank==0){printf("Successfully reduced stuff\n");} if(myrank == 0){ totalFuel = (totalFuel+((totalFuel/100)*10)); printf("Total fuel required: %d\n", totalFuel); } // 释放内存 if(M != NULL){ free(M); } MPI_Finalize(); return 0; }
关键修改说明
- 限定文件操作范围:仅rank=0执行文件打开、读取、关闭操作,非0进程完全不接触文件指针,避免非法访问。
- 修正行数统计:通过
fscanf读取整数计数,确保无论文件最后一行是否有换行符,都能正确统计行数。 - 完善异常处理:rank=0遇到文件打开失败或内存分配失败时,广播
N=-1通知所有进程终止,避免死锁。 - 改用动态数组:替代原代码的变长数组
int M[N],提升跨平台兼容性,非0进程在接收N后再分配对应大小的内存。 - 资源清理:所有进程使用完数组后释放内存,rank=0及时关闭文件,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Justin123
相关产品推荐
相关产品推荐

