我正在学习使用pipe道和pipe道上的这个代码。 该程序使用fork创build两个subprocess。 第一个孩子运行“ls”命令并输出到pipe1。 第二次从pipe1读取运行“wc”并输出到标准输出。
我只是试图在中间添加第三个进程,从pipe1读取,输出到pipe2。 基本上我正在尝试做什么
ls | cat | wc -l
我在做什么:
(ls)stdout -> pipe1 -> stdin(cat)stdout-> stdin(wc -l) -> stdout
没有什么打印到标准输出,程序不会退出。
这是我的代码,其中包含进程#3的更改
int main(int argc, char *argv[]) { int pfd[2]; /* Pipe file descriptors */ int pfd2[2]; if (pipe(pfd) == -1) /* Create pipe */ perror("pipe"); if (pipe(pfd2) == -1) /* Create pipe */ perror("pipe"); /* Fork process 1 and exec ls command write to pfd[1], close pfd[0] */ switch (fork()) { case -1: perror("fork"); case 0: if (close(pfd[0]) == -1) perror("close 1"); // dup stdout on pfd[1] if (pfd[1] != STDOUT_FILENO) { if (dup2(pfd[1], STDOUT_FILENO) == -1) perror("dup2 2"); if (close(pfd[1]) == -1) perror("close 4"); } execlp("ls", "ls", (char *) NULL); perror("execlp ls"); default: break; } /* * Fork process 2 and exec wc command read from pfd[0], close pfd[1] write to pfd[1], close pfd2[0] */ switch (fork()) { case -1: perror("fork"); case 0: // read from pfd[0] if (close(pfd[1]) == -1) perror("close 3"); if (pfd[0] != STDIN_FILENO) { if (dup2(pfd[0], STDIN_FILENO) == -1) perror("dup2 2"); if (close(pfd[0]) == -1) perror("close 4"); } if (pfd2[1] != STDOUT_FILENO) { if (dup2(pfd2[1], STDOUT_FILENO) == -1) perror("dup2 2"); if (close(pfd2[1]) == -1) perror("close 4"); } execlp("cat", "cat", (char *) NULL); perror("execlp cat"); default: break; } /* * Fork process 3 */ switch (fork()) { case -1: perror("fork"); case 0: if (close(pfd2[1]) == -1) perror("close 3"); if (pfd2[0] != STDIN_FILENO) { if (dup2(pfd2[0], STDIN_FILENO) == -1) perror("dup2 2"); if (close(pfd2[0]) == -1) perror("close 4"); } execlp("wc", "wc", "-l", (char *) NULL); perror("execlp wc"); default: break; } /* Parent closes unused file descriptors for pipe, and waits for children */ if (close(pfd[0]) == -1) perror("close 5"); if (close(pfd[1]) == -1) perror("close 6"); if (close(pfd2[0]) == -1) perror("close 5"); if (close(pfd2[1]) == -1) perror("close 6"); if (wait(NULL) == -1) perror("wait 1"); if (wait(NULL) == -1) perror("wait 2"); if (wait(NULL) == -1) perror("wait 3"); exit(EXIT_SUCCESS); }
问题在于你没有在进程3中关闭pfd[1]
,加上close(pfd[1]);
在那个过程3中的情况0将会修复它。
在进程3中,该cat
将从pfd[0]
读取,但在这些进程中有四个pfd[1]
:
进程0
这是主流程,在这个过程中, pfd[1]
将在wait()
之前关闭。
过程1
ls
完成后,这个过程中的pfd[1]
将被操作系统自动关闭。
过程2
在执行cat
之前, pfd[1]
已关闭。
过程3
在wc
运行的时候, pfd[1]
在这个过程中是打开的,这就是在那个时候发生的事情:
cat
尝试从pfd[1]
读取pfd[0]
pfd[1]
wc
尝试从pfd2[1]
读取pfd2[0]
pfd2[1]
pdf[1]
在进程3中仍然打开,并且没有任何内容会写入,所以在进程2(cat)中从pfd[0]
读取将永远等待 cat
还活着,所以从进程3(wc)中的pfd2[0]
读取将等待(永远) 正如您所看到的,由于文件描述符泄漏,您在进程2(cat)和进程3(wc)之间发生死锁。 要打破这个僵局,你只需要在运行wc
之前关闭进程3中的pfd[1]
,之后:
ls
退出之后,进程2中的cat
将退出,因为没有任何东西可以读取 cat
退出之后,进程3中的wc
也将退出,因为没有任何东西可以读取(wc) 有可能有一个以上的管道读取结束写入结束,除非所有这些写入结束都关闭,文件结束将不会传递到读取结束,读者将只是等待更多的数据来。 如果没有什么可说的,那个读者会永远等下去。