2015-08-15 73 views
0

我遇到了管道問題。我正在嘗試執行例如ls | grep測試和我的程序凍結。我的程序是一個shell程序,我得到重定向和其他東西的工作,但我不能讓管道工作...我做錯了什麼?我有搜索答案,但無法找到任何解決我的問題。c中的管道問題

if(pipe(fd_pipe) < 0) 
     perror("pipe error..."); 

    if ((pid = fork()) < 0) /* fork a child process */ 
    {  
     perror("ERROR: forking child process failed\n"); 
     exit(1); 
    } 
    else if (pid == 0) /* the child process, do the first command */ 
    { 
     printf("In first child...\n"); 
     //dupPipe(fd_pipe, 1, STDOUT_FILENO); /* send to write end of pipe */ 

     fflush(stdout); 
     std_out = dup(1); // for later restore... 
     close(fd_pipe[0]); 
     dup2(fd_pipe[1], 1); 


     printf("exec %s in first child...\n", comline[0].argv[0]);   
     if (execvp(comline[0].argv[0], comline[0].argv) < 0) /* execute the command */ 
     { 
      fprintf(stderr,"-mish: Exe of %s failed...",comline[0].argv[0]); 
      fflush(stderr); 
      perror(""); 
     } 

    } 
    else /* parent process*/ 
    { 
     while (wait(&status) != pid) //wait for child to completion 
      ; 

     fflush(stdin); 
     std_in = dup(0); // for later restore... 
     close(fd_pipe[1]); 
     dup2(fd_pipe[0], 0); 


     if (execvp(comline[1].argv[0], comline[1].argv) < 0) /* execute the command */ 
      { 
       fprintf(stderr,"-mish: Exe of %s failed...",comline[0].argv[0]); 
       fflush(stderr); 
       perror(""); 
      } 
+2

從技術上講,對'stdin'調用'fflush'是未定義的。如果你想要便攜,那麼不要這樣做。 –

+0

「我有搜索答案」 - 更難搜索。 [你看到這個問題了嗎?](https://stackoverflow.com/questions/19356075/toy-shell-not-piping-correctly)? – WhozCraig

+0

請注意,您不需要測試'execvp()'或其任何族的返回值。如果函數返回,則失敗;如果成功,它不會返回。您對'for later restore'的評論很奇怪;如果execvp()成功,則不會有'稍後'執行還原。如果命令執行失敗,則更清晰的評論將是'用於恢復',但如果您顯示代碼則更具說服力。 –

回答

0

請注意,Andrew Henleanswer中的註釋長期適用 - 您需要同時運行管道中的所有程序以確保沒有任何死鎖,因爲一個進程正在嘗試寫入完整管道另一個是在執行從管道讀取的代碼(或程序)之前等待一個進程完成。這個問題直接提出的意見也適用。

但是,這個代碼是從你的最小帶幫助中得到的(我沒有註釋掉未使用的變量std_instd_out,儘管),乾淨地編譯並運行併產生合理的輸出。

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/wait.h> 

struct cmd 
{ 
    char **argv; 
}; 

int main(void) 
{ 
    int fd_pipe[2]; 
    int pid; 
    //int std_in; 
    //int std_out; 
    int status; 
    char *cmd1[] = { "ls", 0 }; 
    char *cmd2[] = { "grep", "test", 0 }; 
    struct cmd comline[2] = { { cmd1 }, { cmd2 } }; 

    if(pipe(fd_pipe) < 0) 
     perror("pipe error..."); 

    if ((pid = fork()) < 0) /* fork a child process */ 
    {  
     perror("ERROR: forking child process failed\n"); 
     exit(1); 
    } 
    else if (pid == 0) /* the child process, do the first command */ 
    { 
     printf("In first child...\n"); 
     //dupPipe(fd_pipe, 1, STDOUT_FILENO); /* send to write end of pipe */ 

     fflush(stdout); 
     //std_out = dup(1); // for later restore... 
     close(fd_pipe[0]); 
     dup2(fd_pipe[1], 1); 

     printf("exec %s in first child...\n", comline[0].argv[0]);   
     if (execvp(comline[0].argv[0], comline[0].argv) < 0) /* execute the command */ 
     { 
      fprintf(stderr,"-mish: Exe of %s failed...",comline[0].argv[0]); 
      fflush(stderr); 
      perror(""); 
     } 
     exit(EXIT_FAILURE); 

    } 
    else /* parent process*/ 
    { 
     while (wait(&status) != pid) //wait for child to completion 
      ; 

     fflush(stdin); 
     //std_in = dup(0); // for later restore... 
     close(fd_pipe[1]); 
     dup2(fd_pipe[0], 0); 

     if (execvp(comline[1].argv[0], comline[1].argv) < 0) /* execute the command */ 
     { 
      fprintf(stderr,"-mish: Exe of %s failed...",comline[0].argv[0]); 
      fflush(stderr); 
      perror(""); 
     } 
     exit(EXIT_FAILURE); 
    } 
    printf("Exiting from %d\n", (int)getpid()); 
    return 0; 
} 

在有130多名的文件(讓來自ls輸出的約1.5昆明植物研究所)的目錄,我得到:

$ ./p97 
In first child... 
chk-utf8-test.sh 
chk-wchar-test.sh 
pbb-test.data 
test-fstatat.c 
test-rename.c 
utf8-test.c 
wchar-test.c 
$ 

這是我從運行ls | grep test除了在命令行中獲得(中當然)從診斷消息。

但是我的懷疑是你沒有向我們展示所有的代碼。 std_instd_out變量讓我懷疑實際上還有其他一些代碼,並且可能pipe()操作發生在父進程中,然後子進程分叉,然後子進程運行問題中顯示的其餘代碼。如果出現這種情況,那麼命令沒有完成可能會出現問題,因爲管道未正確關閉。

+0

謝謝你的答案,它現在的作品:)。 std_in和std_out將它恢復爲STDIN和STDOUT以備後用。再次感謝!! – Christer

0

當第一個子進程仍在運行時,您正在調用wait()。這意味着沒有什麼東西會讀取第一個孩子寫入其stdout的任何內容 - 如果管道填滿,第一個孩子進程將阻止寫入stdout。但由於第一個孩子的父母過程是wait(),所以你會陷入僵局。

+0

這是(至少)一個潛在的問題;這將需要解決。管道的元素應該同時運行。我不確定這是唯一的問題,如果'ls'的輸出小於大約5 KiB,這也是一個很大的目錄列表。 –