使用pipe()实现任意数量子进程间整数传递的问题求解
C语言使用pipe实现多子进程链式管道通信问题
我希望通过pipe()在多个子进程之间传递数据,效果如下:
该实现需要支持任意数量的子进程,要求子进程打印从管道读取到的数值,将数值加1后传递给下一个进程。
目前遇到以下3个问题:
- 子进程函数被以相同参数多次调用
- 该问题导致文件描述符发生非预期变更
- 除第一个进程外,其余所有进程操作时errno返回
Bad file descriptor
第一个进程运行一切正常,可以从父进程接收数值,向writePipe写入时也没有报错。
程序运行的控制台输出如下:
id:0 pipeRead:5 PipeWrite:8 id:0 res:4 value:500 id:1 pipeRead:9 PipeWrite:12 id:2 pipeRead:13 PipeWrite:16 id:1 pipeRead:3 PipeWrite:6 id:2 pipeRead:7 PipeWrite:10 id:1 res:-1 value:0 id:2 pipeRead:3 PipeWrite:6 id:2 res:-1 value:0 Read Error: Bad file descriptor Read Error: Bad file descriptor
原代码实现如下:
int execChild(int appID, int pipeRead[2], int pipeWrite[2]){ //Before start process, I close read/write that not used here //Close write of read pipe close(pipeRead[1]); //Close read of write pipe close(pipeWrite[0]); printf("id:%d pipeRead:%d PipeWrite:%d\n",appID,pipeRead[0],pipeWrite[1]); int buff=0; long int res; res = read(pipeRead[0],&buff,sizeof(int)); if (res==-1) perror("Read Error"); //Close read pipe after used close(pipeRead[0]); printf("id:%d res:%ld value:%d\n",appID,res,buff); //Increment value buff += 1; res = write(pipeWrite[1],&buff,sizeof(int)); if(res==-1)perror("Write Error"); //Close write pipe after used close(pipeWrite[1]); return 0; } int main(int argc, char *argv[]) { int nbFis = 3; //Init array of pipeArray with malloc int* pipeArr[nbFis]; for (int i = 0; i < nbFis; i++) pipeArr[i] = (int*)malloc(2 * sizeof(int)); for (int i = 0; i < nbFis; i++) // Generate n child { //Here we open every inter child pipe //If the process is 0 we need to open the last pipe of the array //Else we open the last pipe if(i==0){ pipe(pipeArr[nbFis-1]);//Open Read Pipe //To test I inject an int value here to child 0 int value = 500; write(pipeArr[nbFis-1][1],&value,sizeof(int));//Write value in the pipe }else{ pipe(pipeArr[i-1]);//Open Read Pipe } pipe(pipeArr[i]);//Open Write Pipe if (fork() == 0) { //If it's the first child we send the last pipe in the array as read pipe and current pipe as write pipe //Else we send the previous pipe in the list as read pipe and current pipe as write pipe if(i==0){ execChild(i,pipeArr[nbFis-1],pipeArr[i]); }else{ execChild(i,pipeArr[i-1],pipeArr[i]); } } } //Wait for the end of process and free memory for (int i = 0; i < nbFis; i++) { free(pipeArr[i]); wait(NULL); } return 0; }
问题原因
- 子进程未主动退出:子进程调用完
execChild后没有调用exit(),会继续执行外层的for循环逻辑,重复创建更多子进程,这是子进程函数被多次调用的核心原因。 - 管道创建逻辑错误:在循环创建子进程的过程中重复创建管道,同一个管道索引的文件描述符会被多次覆盖,导致后续子进程拿到的fd是已失效的错误值。
- 无用文件描述符未关闭:父子进程都没有关闭自身用不到的管道端,管道引用计数异常,既会导致fd泄露,也会引发读写操作异常。
修复后代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int execChild(int appID, int pipeRead[2], int pipeWrite[2]){ close(pipeRead[1]); close(pipeWrite[0]); printf("id:%d pipeRead:%d PipeWrite:%d\n", appID, pipeRead[0], pipeWrite[1]); int buff = 0; ssize_t res; res = read(pipeRead[0], &buff, sizeof(int)); if (res == -1) perror("Read Error"); close(pipeRead[0]); printf("id:%d res:%ld value:%d\n", appID, (long)res, buff); buff += 1; res = write(pipeWrite[1], &buff, sizeof(int)); if(res == -1) perror("Write Error"); close(pipeWrite[1]); return 0; } int main(int argc, char *argv[]) { int nbFis = 3; // 提前一次性创建所有需要的管道 int pipeArr[nbFis][2]; for (int i = 0; i < nbFis; i++) { if(pipe(pipeArr[i]) == -1) { perror("pipe create error"); exit(1); } } // 写入初始值到第一个子进程的读管道 int value = 500; write(pipeArr[nbFis-1][1], &value, sizeof(int)); close(pipeArr[nbFis-1][1]); for (int i = 0; i < nbFis; i++) { pid_t pid = fork(); if (pid == -1) { perror("fork error"); exit(1); } if (pid == 0) { // 子进程先关闭所有用不到的管道 for(int j=0; j<nbFis; j++) { if(i == 0) { if(j != nbFis-1 && j != 0) { close(pipeArr[j][0]); close(pipeArr[j][1]); } } else { if(j != i-1 && j != i) { close(pipeArr[j][0]); close(pipeArr[j][1]); } } } if(i == 0){ execChild(i, pipeArr[nbFis-1], pipeArr[i]); }else{ execChild(i, pipeArr[i-1], pipeArr[i]); } // 子进程执行完成直接退出,不执行后续父进程逻辑 exit(0); } } // 父进程关闭所有管道端 for(int i=0; i<nbFis; i++) { close(pipeArr[i][0]); close(pipeArr[i][1]); } // 等待所有子进程退出 for (int i = 0; i < nbFis; i++) { wait(NULL); } return 0; }
内容的提问来源于stack exchange,提问作者MrSolarius
相关产品推荐
相关产品推荐

