2016-04-27 82 views
1

我需要實現這樣的IPC架構:多管道不工作

runtime data -> filter1 -> filter2 -> output。 (與data | filter1 | filter2相同)。

我可以將數據傳遞給第一個篩選器,但對於第二個我不能(可能是因爲在第一個子標準輸出fd沒有關閉)。如何正確實現這樣的模式?

P.S. filter1和filter2只是從標準輸入讀取並寫入標準輸出。

我的代碼:

int main() { 
    int fd1[2]; 
    pipe(fd1); 
    pid_t pid1; 

    if ((pid1 = fork()) > 0) { 
     char data[] = "Hello world!"; 

     close(fd1[0]); 
     write(fd1[1], data, sizeof(data)); 
     close(fd1[1]); 
     wait(NULL); 
     exit(EXIT_SUCCESS); 

    } else if (pid1 == 0) { 
     int fd2[2]; 
     pipe(fd2); 
     pid_t pid2; 

     dup2(fd1[0], STDIN_FILENO); 
     dup2(fd2[1], STDOUT_FILENO); 
     close(fd1[0]); close(fd1[1]); 
     close(fd2[0]); close(fd2[1]); 

     if ((pid2 = fork()) > 0) { 
      execl("./upcase", "upcase", NULL); 
      perror("execl"); 
      exit(EXIT_FAILURE); 
     } else if (pid2 == 0) { 
      close(fd1[0]); close(fd1[1]); 

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

      execl("./reverse", "reverse", NULL); 
      perror("execl"); 
      exit(EXIT_FAILURE); 
     } else { 
      perror("pid2"); 
      exit(EXIT_FAILURE); 
     } 

    } else { 
     perror("pid1"); 
     exit(EXIT_FAILURE); 
    } 

} 
+0

「*也許是因爲在第一個孩子的stdout FD沒有關閉*」 - 好像你已經發現的問題。由於第一個過濾器從來沒有在其輸入管道上看到EOF(因爲它被另一個進程保持打開),所以它永遠不會完成。 – Dolda2000

+0

@ Dolda2000是的,但我怎樣才能關閉標準輸出外部進程? – 0x1337

+0

您已經在最親的過程中關閉了它;問題似乎是你不會在你的「反向」孩子中關閉它。 – Dolda2000

回答

1

你太早關閉管道。通常,在dup2中使用它之前,請關閉fd2[0]。並且,當您在第二個分支之前重定向FILENO_STDOUT時,第二個過濾器不再能夠訪問原始標準輸出。

下面的代碼工作:

int main() { 
    int fd1[2]; 
    pipe(fd1); 
    pid_t pid1; 

    if ((pid1 = fork()) > 0) { 
     char data[] = "Hello world!"; 

     close(fd1[0]); // OK, will no longer be used 
     write(fd1[1], data, sizeof(data)); 
     close(fd1[1]); 
     wait(NULL); 
     exit(EXIT_SUCCESS); 

    } else if (pid1 == 0) { 
     int fd2[2]; 
     pipe(fd2); 
     pid_t pid2; 
     close(fd1[1]); // OK, no used from here 

     if ((pid2 = fork()) > 0) { 
     dup2(fd1[0], STDIN_FILENO); // redirections for filter1 
     dup2(fd2[1], STDOUT_FILENO); 
     close(fd1[0]);    // close everything except stdin and stdout 
     close(fd2[0]); close(fd2[1]); 
      execl("./upcase", "upcase", NULL); 
      perror("execl upcase"); 
      exit(EXIT_FAILURE); 
     } else if (pid2 == 0) { 
      close(fd1[0]);    // not used here 

      dup2(fd2[0], STDIN_FILENO); // redirection for filter2 
      close(fd2[0]); close(fd2[1]); // close all what remains 

      execl("./reverse", "reverse", NULL); 
      perror("execl reverse"); 
      exit(EXIT_FAILURE); 
     } else { 
      ...