我想在3个子进程之间创建两个管道,但我首先想要让第一个管道pipe1
在两个fork进程之间工作。问题是当我从第一个进程复制stdout并同样从另一个进程复制stdin时,我没有得到输出。
int main()
{
int pipe1[2];
int pipe2[2];
pipe(pipe1);
pipe(pipe2);
sem_t mutex_pipe1;
sem_t mutex_pipe2;
sem_init(&mutex_pipe1, 0, 0);
sem_init(&mutex_pipe2, 0, 1);
if (fork()==0) { //process 1
close(1); /* close normal stdout */
dup(pipe1[1]); /* make stdout same as pfds[1] */
sem_post(&mutex_pipe1);
execlp("ls", "ls", NULL);
}
if (fork()==0){ //process 2
sem_wait(&mutex_pipe1);
close(0);
dup(pipe1[0]);
dup2(pipe1[1], 1) //want to open stdout again.
sem_post(&mutex_pipe1);
execlp("wc", "wc", "-l", NULL);
}
答案 0 :(得分:4)
您的信号量在您提供的代码中没有对您有用。我不清楚你甚至认为他们会做什么,特别是一旦你的孩子进程调用exec()
- 家庭功能。
此外,一旦关闭,你不能再“打开stdout”。您可以将文件描述符1(以及stdout
)与不同的文件相关联,但是一旦关闭了与其关联的所有FD,您就无法获取文件,除非open()
或{{1再来一次。
然而,您似乎并不意识到在fopen()
之后,子进程和父进程不共享内存,至少在一个普通内存写入的意义上是不可见的。因此,在原始代码中,当第一个孩子关闭其fork()
时,父母不会受到影响,第二个孩子不会继承任何更改或需要恢复原始stdout
。
另一方面,请注意,当您stdout
子进程,并且它继承了父进程的打开文件描述符时,会导致两个进程打开每个文件描述符。此外,当您对FD进行欺骗时,您会在同一文件上打开第二个FD。在基础打开文件关闭之前,您需要关闭它们的所有,否则可能会产生不良影响。特别是在您的情况下,您的第二个子进程挂起,因为它正在等待另一侧的fork()
关闭,虽然第一个子进程关闭其副本,但父进程仍然持有一个开放的FD。 stdin
程序在消耗完整个输入之前不会产生任何输出。你可能会看到一些输出,如果你是exec'ing,比如wc
。
此外,父级通常应该在退出之前等待其子进程完成,并且如果它继续执行其他工作,它必须最终等待它们在它们之后进行清理。
最后,总是总是检查错误代码的返回值。
以下是如何设置一对通过管道单向通信的子进程的最小版本:
cat
答案 1 :(得分:0)
感谢John Bollinger的灵感。以下是使用三个子进程和两个管道执行ls|sort|less|
:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define DIE do { perror(NULL); exit(1); } while (0)
#define DO_OR_DIE(f) do { if ((f) < 0) DIE; } while (0)
int main(void)
{
int pipe1[2]; //pipe1
int pipe2[2]; //pipe2
DO_OR_DIE(pipe(pipe1)); //initialize pipe1
DO_OR_DIE(pipe(pipe2)); //initialize pipe2
switch (fork()) {
case -1: // failed to fork
DIE;
case 0: // child process 1
/* make stdout a copy of the write end of pipe1 */
DO_OR_DIE(dup2(pipe1[1], STDOUT_FILENO));
/* close the excess file descriptor */
DO_OR_DIE(close(pipe1[1]));
execlp("ls", "ls", NULL);
/* execlp returns only on failure */
DIE;
/* default: parent process */
}
/* close the parent's copy of pipe1 write end. Avoids child2 hanging */
DO_OR_DIE(close(pipe1[1]));
switch (fork()) {
case -1: // failed to fork
DIE;
case 0: // child process 2
/* make stdin a copy of the read end of pipe1 */
DO_OR_DIE(dup2(pipe1[0], STDIN_FILENO));
/* close the excess file descriptor */
DO_OR_DIE(close(pipe1[0]));
/* make stdout a copy of the write end of pipe2 */
DO_OR_DIE(dup2(pipe2[1], STDOUT_FILENO));
/* close the excess file descriptor */
DO_OR_DIE(close(pipe2[1]));
execlp("sort", "sort", NULL);
/* execlp returns only on failure */
DIE;
/* default: parent process */
}
/* close the parent's copy of pipe1 read end, for consistency and tidiness*/
DO_OR_DIE(close(pipe1[0]));
/* close the parent's copy of pipe2 write end. Avoids child3 hanging */
DO_OR_DIE(close(pipe2[1]));
switch (fork()) {
case -1: // failed to fork
DIE;
case 0: // child process 3
/* make stdin a copy of the read end of pipe2 */
DO_OR_DIE(dup2(pipe2[0], STDIN_FILENO));
/* close the excess file descriptor */
DO_OR_DIE(close(pipe2[0]));
execlp("less", "less", NULL);
/* execlp returns only on failure */
DIE;
/* default: parent process */
}
/* close the parent's copy of pipe2 read end, for consistency and tidiness*/
DO_OR_DIE(close(pipe2[0]));
/* wait for child processes to stop */
DO_OR_DIE(wait(NULL));
DO_OR_DIE(wait(NULL));
DO_OR_DIE(wait(NULL));
return 0;
}