学习pipe道,执行,分叉,并试图将三个进程链接在一起

我正在学习使用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]

  1. 进程0

    这是主流程,在这个过程中, pfd[1]将在wait()之前关闭。

  2. 过程1

    ls完成后,这个过程中的pfd[1]将被操作系统自动关闭。

  3. 过程2

    在执行cat之前, pfd[1]已关闭。

  4. 过程3

    wc运行的时候, pfd[1]在这个过程中是打开的,这就是在那个时候发生的事情:

    1. 在进程2中, cat尝试从pfd[1]读取pfd[0] pfd[1]
    2. 在进程3中, wc尝试从pfd2[1]读取pfd2[0] pfd2[1]
    3. 因为pdf[1]在进程3中仍然打开,并且没有任何内容会写入,所以在进程2(cat)中从pfd[0]读取将永远等待
    4. 因为进程3中的cat还活着,所以从进程3(wc)中的pfd2[0]读取将等待(永远)

正如您所看到的,由于文件描述符泄漏,您在进程2(cat)和进程3(wc)之间发生死锁。 要打破这个僵局,你只需要在运行wc之前关闭进程3中的pfd[1] ,之后:

  1. 在进程1中的ls退出之后,进程2中的cat将退出,因为没有任何东西可以读取
  2. 在进程2中的cat退出之后,进程3中的wc也将退出,因为没有任何东西可以读取(wc)
  3. 之后,主进程(父进程)将退出,程序结束。

有可能有一个以上的管道读取结束写入结束,除非所有这些写入结束都关闭,文件结束将不会传递到读取结束,读者将只是等待更多的数据来。 如果没有什么可说的,那个读者会永远等下去。