2016-10-02 61 views
0

我会执行这个命令ls -al/| tr a-j A-J | tr k-z K-Z,我会从父进程创建三个孩子。三个孩子之间的管道

我知道,我已经打开两个管道,让父亲等待他的所有儿童(关闭所有的管道)和我已经到

  • 接近STDIN第一个孩子的孩子
  • 接近STDOUT在第一管和STDIN第二管,在第二个孩子
  • 接近STDOUT的第三个孩子

现在,这是我的代码。如果我只有两个孩子运行它,它的工作原理。但是,如果我尝试与三个孩子一起运行,它不起作用。

// command is ls -al/| tr a-j A-J | tr k-z K-Z 

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

int main(int argc, char **argv) { 
int fd1[2]; 
int fd2[2]; 
pid_t pid = 0; 

pipe(fd1); 
pipe(fd2); 

pid = fork(); 
if(pid == 0) { 
    close(fd1[0]); 
    dup2(fd1[1], 1); 
    close(fd1[1]); 

    execlp("ls", "ls", "-al", "/", NULL); 
} 

pid = fork(); 
if(pid == 0) { 
    close(fd1[1]); 
    dup2(fd1[0], 0); 
    close(fd1[0]); 

    close(fd2[0]); 
    dup2(fd2[1], 1); 
    close(fd2[1]); 

    execlp("tr", "tr", "a-j", "A-J", NULL); 
} 

pid = fork(); 
if(pid == 0) { 
    close(fd2[1]); 
    dup2(fd2[0], 0); 
    close(fd2[0]); 

    execlp("tr", "tr", "k-z", "K-Z", NULL); 
} 

close(fd1[0]); 
close(fd1[1]); 
close(fd2[0]); 
close(fd2[1]); 

while ((pid = wait(NULL)) != -1); 

exit(0); 
} 

在此先感谢您。

+0

您从不关闭父级中的任何管道末端。正在读取管道的孩子正在等待管道的所有*写入结束关闭,但父母仍然保持着一端打开。关闭它。 –

+0

我最后关闭了管道。我必须在开始时关闭它们? –

+0

在管道的所有写入结束都关闭之前,tr'不会终止。如果父'等待'tr'终止,则它必须在等待之前关闭管道的末端,否则这两个过程将会死锁。 –

回答

0

您可以使用pipe2()并设置close_on_exec标志。下面的代码工作:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <fcntl.h> 

int main(int argc, char **argv) { 
    int fd1[2]; 
    int fd2[2]; 
    pid_t pid = 0; 

    pipe2(fd1,O_CLOEXEC); 
    pipe2(fd2,O_CLOEXEC); 

    pid = fork(); 
    if(pid == 0) { 
    dup2(fd1[1],1); 
    execlp("ls", "ls", "-al", "/", NULL); 
    } 

    pid = fork(); 
    if(pid == 0) { 
    dup2(fd1[0],0); 
    dup2(fd2[1],1); 
    execlp("tr", "tr", "a-j", "A-J", NULL); 
    } 

    pid = fork(); 
    if(pid == 0) { 
    dup2(fd2[0],0); 
    execlp("tr", "tr", "k-z", "K-Z", NULL); 
    } 

    close(fd1[0]); 
    close(fd1[1]); 
    close(fd2[0]); 
    close(fd2[1]); 

    while ((pid = wait(NULL)) != -1); 

    exit(0); 
} 

它可以使用管()调用也,但你应该小心无处不在手动关闭描述符,这是很容易出错(你证明,通过发布这个问题; - )):

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

int main(int argc, char **argv) { 
    int fd1[2]; 
    int fd2[2]; 
    pid_t pid = 0; 

    pipe(fd1); 
    pipe(fd2); 

    pid = fork(); 
    if(pid == 0) { 
    close(fd1[0]); 
    dup2(fd1[1], 1); 
    close(fd1[1]); 

    execlp("ls", "ls", "-al", "/", NULL); 
    } 

    pid = fork(); 
    if(pid == 0) { 
    close(fd1[1]); 
    dup2(fd1[0], 0); 
    close(fd1[0]); 

    close(fd2[0]); 
    dup2(fd2[1], 1); 
    close(fd2[1]); 

    execlp("tr", "tr", "a-j", "A-J", NULL); 
    } 

    pid = fork(); 
    if(pid == 0) { 
    close(fd1[0]); 
    close(fd1[1]); 
    close(fd2[1]); 
    dup2(fd2[0], 0); 
    close(fd2[0]); 

    execlp("tr", "tr", "k-z", "K-Z", NULL); 
    } 

    close(fd1[0]); 
    close(fd1[1]); 
    close(fd2[0]); 
    close(fd2[1]); 

    while ((pid = wait(NULL)) != -1); 
} 
+0

包含指向相关手册页的链接会很有帮助(例如['pipe2()'](http://man7.org/linux/man-pages/man2/pipe.2.html))。 –

+0

谢谢。但是,如果我只使用'pipe()'而不是'pipe2()',该怎么办? –

+0

@FedericoCuozzo:如果您使用'pipe()'而不是'pipe2()',那么您需要在执行子代之前关闭未使用的管道描述符。在实践中,这意味着你已经使用'dup()'或(更可能)'dup2()'将管道描述符复制到标准输入或标准输出中,在你之前需要关闭管道中的文件描述符_all_使用'execvp()'或其他。请注意'execlp()'的值是有限的;你必须在编译时知道(上限)参数的数量 - 'execvp()'是更通用的接口。为了您的直接目的,'execlp()'是可以的。 –