2016-10-02 52 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()'是可以的。 –