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

链式多进程统计文件行/词/字符数 pipe传值累加异常问题求助

错误根源

  1. 子进程处理完当前文件逻辑后未调用exit()主动退出,会继续执行后续循环代码,重复创建新进程、重复打印日志。
  2. 进程的地址空间相互独立,子进程对本地累加变量的修改无法同步到父进程,仅靠父进程本地累加无法拿到所有子进程的统计值。
  3. 原有break逻辑仅让主进程拿到第一个子进程的统计值就终止循环,因此总和仅包含第一个文件的统计结果;删除break后所有进程都会继续执行fork逻辑,进程数指数级增长,因此会出现多次重复打印。

符合链式进程要求的修复代码

int send[3], get[3];
int fd[2];
int totLines = 0, totWords = 0, totChars = 0;
int i;
pid_t pid;

// filenames为存储所有待统计文件名的数组
for (i = 0; i < n; i++) {
    pipe(fd);
    pid = fork();
    if (pid < 0) {
        perror("fork");
        exit(1);
    } else if (pid == 0) {
        // 处理当前第i个文件的统计
        countFile(filenames[i], send);
        printf("PID: %d - PPID: %d - %s l=%d w=%d c=%d\n", getpid(), getppid(), filenames[i], send[0], send[1], send[2]);
        
        int curL = send[0], curW = send[1], curC = send[2];
        int subTot[3] = {0};
        close(fd[0]);

        // 非最后一个进程,需要创建下一级子进程获取后续统计总和
        if (i < n - 1) {
            int sub_fd[2];
            pipe(sub_fd);
            pid_t sub_pid = fork();
            if (sub_pid < 0) {
                perror("sub fork");
                exit(1);
            } else if (sub_pid == 0) {
                // 下一级子进程回到循环处理i+1个文件
                close(sub_fd[1]);
                continue;
            } else {
                close(sub_fd[1]);
                read(sub_fd[0], subTot, sizeof(subTot));
                close(sub_fd[0]);
                wait(NULL);
            }
        }

        // 累加自身统计值和后续子进程的统计总和,传给上级父进程
        send[0] = curL + subTot[0];
        send[1] = curW + subTot[1];
        send[2] = curC + subTot[2];
        write(fd[1], send, sizeof(send));
        close(fd[1]);
        // 子进程任务完成,主动退出避免执行后续父进程逻辑
        exit(0);
    } else {
        // 上级父进程读取当前子进程返回的累加总和
        close(fd[1]);
        read(fd[0], get, sizeof(get));
        totLines = get[0];
        totWords = get[1];
        totChars = get[2];
        close(fd[0]);
        // 父进程无需再创建子进程,跳出循环
        break;
    }
}

// 仅最顶层的主进程执行打印总和逻辑
if (pid != 0) {
    for (i = 0; i < n; i++) {
        wait(NULL);
    }
    printf("Total: l=%d w=%d c=%d\n", totLines, totWords, totChars);
}

核心修改点

  • 每个子进程完成统计、传递数据后主动调用exit(0)退出,避免重复执行逻辑。
  • 非最后一个子进程会创建下一级子进程,拿到后续所有文件的统计总和后,加上自身统计值再向上传递,最终主进程拿到的就是所有文件的统计总和。
  • 仅最顶层的主进程会执行总和打印逻辑,避免重复打印。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 10:57:05