我正在学习使用管道并在pipes上跟随此代码。该程序使用fork生成两个子进程。第一个孩子跑步' ls'命令和输出到pipe1。从pipe1运行的第二个读取' wc'并输出到stdout。
我只是试图在中间添加第三个进程,从pipe1读取并输出到pipe2。基本上我正在尝试做什么
ls | cat | wc -l
我想做的事情:
(ls)stdout -> pipe1 -> stdin(cat)stdout-> stdin(wc -l) -> stdout
什么都没有打印到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);
}
答案 0 :(得分:2)
问题是你没有在流程3中关闭pfd[1]
,在案例0之后添加close(pfd[1]);
,因为流程3会修复它。
在流程3中,cat
将从pfd[0]
读取,但在这些流程中有四个pfd[1]
:
流程0
这是主要流程,此过程中的pfd[1]
将在wait()
之前关闭。
流程1
ls
完成后,此过程中的pfd[1]
将由操作系统自动关闭。
流程2
pfd[1]
在执行cat
之前已经关闭。
流程3
当pfd[1]
正在运行时, wc
在此过程中处于打开状态,这就是当时发生的事情:
cat
尝试阅读pfd[0]
来自pfd[1]
的数据wc
尝试阅读pfd2[0]
来自pfd2[1]
的数据pdf[1]
仍在进程3中打开,并且没有任何内容会被写入,所以在进程2(cat)中从pfd[0]
读取将永远等待cat
仍然存在,所以在进程3(wc)中从pfd2[0]
读取将等待(永远)如您所见,由于文件描述符泄漏,您在进程2(cat)和进程3(wc)之间存在死锁。要打破这种僵局,您只需在流程3中关闭pfd[1]
,然后再运行wc
:
cat
将在进程1中的ls
退出后退出,因为没有任何内容(cat)可以阅读cat
退出后,流程3中的wc
也将退出,因为没有任何内容(wc)可以阅读管道的读取端可能有多个写入结束,除非所有这些写入结束都关闭,文件结束将不会传送到读取端,读者只会等待获得更多数据。如果没有任何事情要发生,那读者将永远等待。