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

为何最后一个子进程退出前无法执行?管道与子进程问题排查

管道与子进程同步问题的修复方案

问题根源分析

你的代码存在几个关键问题,直接导致管道通信失效、进程永久阻塞:

  1. 未初始化管道:仅定义了pipefd数组,但从未调用pipe(pipefd)创建管道,子进程的write操作实际是往无效文件描述符写入,父进程自然读不到数据。
  2. wait调用位置错误:wait(NULL)放在循环外,仅能等待一个子进程退出,剩余9个子进程会变成僵尸进程;且父进程在read完成后才执行wait,但read因管道未正确初始化一直阻塞。
  3. 管道复用逻辑错误:多子进程共享未重置的管道会导致读写混乱,应为每个子进程创建独立管道。

修复步骤与代码示例

关键修改点:

  • 在每次fork前调用pipe(pipefd)创建新管道
  • 将wait操作放入循环内,确保每个子进程退出后父进程及时回收
  • 父/子进程分别关闭不需要的管道端,避免管道引用计数异常导致read阻塞
  • 增加系统调用的错误检查,方便调试

修复后的完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
#include <time.h>

// MACRO
#define MESSAGE_DATA "msg1"

// 补充原代码缺失的get_random函数
int get_random(int min, int max) {
    return min + rand() % (max - min + 1);
}

void *Hangar(void *arg){
    char msgSend[128];
    int msgLength = strlen(MESSAGE_DATA);
  
    printf("Hangar: Sto contattando la torre di controllo\n");

    // 循环创建10个子进程,每个子进程对应独立管道
    for(int i=0; i<10; i++){
        int pipefd[2];
        // 初始化管道并检查错误
        if(pipe(pipefd) == -1){
            perror("pipe failed");
            exit(EXIT_FAILURE);
        }

        sleep(2);
        printf("\tAttesa: In corso preparativi: pulizia-controllo dispositivi, imbarco vivande...\n");
        sleep(get_random(3,8));
    
        pid_t pid = fork();
        if(pid == -1){
            perror("fork failed");
            exit(EXIT_FAILURE);
        }
        else if(pid == 0){ // 子进程(aereo)
            // 关闭读端,仅保留写端
            close(pipefd[0]);
            
            printf("\nArrivo dell'aereo %d, proveniente dall'hangar %d\n", getpid(), getppid());
            printf("Invio notifica dello stato degli aerei all'hangar di partenza\n");
            
            strcpy(msgSend, MESSAGE_DATA);
            printf("msgSend: %s\n", msgSend);
            
            // 写入管道并检查结果
            ssize_t bytes_written = write(pipefd[1], msgSend, msgLength);
            if(bytes_written == -1){
                perror("write failed");
            }
            // 关闭写端,触发父进程read返回
            close(pipefd[1]);
          
            exit(0);
        }
        else{ // 父进程(hangar)
            // 关闭写端,仅保留读端
            close(pipefd[1]);
            
            memset(msgSend, '\0', sizeof(msgSend));
            // 读取管道数据
            ssize_t bytes_read = read(pipefd[0], msgSend, msgLength);
            if(bytes_read == -1){
                perror("read failed");
            }
            else{
                printf("Fine Esecuzione: Messaggio ricevuto -> %s\n", msgSend);
            }
            // 关闭读端
            close(pipefd[0]);
            
            // 等待当前子进程退出,避免僵尸进程
            waitpid(pid, NULL, 0);
        }
    }

    pthread_exit(0);
}

int main(int argc, char **argv){
    // 初始化随机数种子
    srand(time(NULL));

    pthread_t t_hangar;
    pthread_create(&t_hangar, NULL, Hangar, NULL);
    pthread_join(t_hangar, NULL);

    return 0;
}

额外说明

  • 补充了get_random函数的实现,原代码未提供该函数会导致编译错误
  • 使用waitpid指定等待当前子进程,比wait(NULL)更精准,确保父进程按顺序处理每个子进程的消息和退出状态
  • 每个子进程使用独立管道,避免多进程同时读写同一管道的冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 13:55:18