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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 16:40:37