为何最后一个子进程退出前无法执行?管道与子进程问题排查
管道与子进程同步问题的修复方案
问题根源分析
你的代码存在几个关键问题,直接导致管道通信失效、进程永久阻塞:
- 未初始化管道:仅定义了
pipefd数组,但从未调用pipe(pipefd)创建管道,子进程的write操作实际是往无效文件描述符写入,父进程自然读不到数据。 - wait调用位置错误:
wait(NULL)放在循环外,仅能等待一个子进程退出,剩余9个子进程会变成僵尸进程;且父进程在read完成后才执行wait,但read因管道未正确初始化一直阻塞。 - 管道复用逻辑错误:多子进程共享未重置的管道会导致读写混乱,应为每个子进程创建独立管道。
修复步骤与代码示例
关键修改点:
- 在每次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
相关产品推荐
相关产品推荐

