2011-05-05 162 views
4

該項目的目標是使用管道和叉執行已經寫入多進程方式的線計數實用程序(每一個參數處理)。我目前正致力於在擴展處理多個參數之前讓單個進程工作。管道和叉

給定兩個可執行文件,lc1lc2,我想lc2建立一個管道的lc1標準輸出文件描述符,這樣當execlp("lc1", argv[1], NULL)被調用時,輸出將被
while ((c= read(pipefd[0], readin, SIZE)) > 0)

根據閱讀我的Unix的書,我應該用開放的,DUP2,close方法重定向標準輸出到標準輸入,這裏是我的代碼:

int pid, c, i; 
char *readin= (char *)malloc(sizeof(SIZE)); 

if (pipe(pipefd)== -1) 
    perror("Can't open a pipe\n"); 

for (i=1; i< argc; i++){ 
if ((pid= fork())==-1) 
     perror("Can't fork\n"); 

    run(argv[i]); 

} 

//close pipe 
close(1); 
if (dup2(pipefd[0], 0)==-1) 
    perror("Can't redirect stdin"); 
close(pipefd[1]); 

for (i=1; i< argc; i++){ 
    if ((wait(NULL))== -1) 
     perror("Wait error"); 

    while ((c= read(pipefd[0], readin, SIZE)) > 0){; 
     //print buf count 
     total += atoi(readin); 
    } 
} 

run函數是

void run(char *f){ 
    int fp; 
    if ((fp= open(f, O_RDONLY)) == -1) 
     perror("Can't open the file"); 

    close(pipefd[0]); 
    dup2(pipefd[1], 1); 
    close(pipefd[1]); 
    execlp("ls1", f, NULL); 
} 

當我嘗試執行此代碼時,出現stdin重定向錯誤,指出文件描述符不正確。爲什麼會發生這種情況,並希望得到解決的任何提示。

+1

你malloc的說法是錯誤的,我認爲你想字符'*閱讀下載=(的char *)malloc的(大小);' – GWW 2011-05-05 17:16:33

+1

在C.見決不投malloc()函數的返回值http://stackoverflow.com/questions/953112/should-i-explicitly-cast-mallocs-return-value/954785#954785。 – unwind 2011-05-05 17:30:30

+0

不是你的直接問題,但你真的指malloc(sizeof(SIZE))嗎?我假設SIZE是一個常量,所以你分配4或8個字節左右。你可以發佈稍微更完整的代碼嗎?正如發佈,這是有點難以遵循。 – Duck 2011-05-05 18:02:32

回答

2

RUN(argv的[I])被兩個父母和孩子,因爲未分配基於返回的PID的功能執行,因此一個接一個緊密可能已經關閉。 看到下面的代碼,他可以很方便,我將使用代碼示例來處理這種情況。 :

int main() 
{ 
    int pipe_fd[2] = {0}; 
    int pid = -1; 
    int status = -1; 
    int ret_value = INVALID_CMD; 
    int cmd_output_len = -1; 
    status = pipe(pipe_fd); 
    if(status<0) 
    { 
     perror("pipe create err"); 
    } 
    else 
    { 
     pid = fork(); 
     if(pid<0) 
     { 
     } 
     else if (pid == 0) 
     { 
      /*Child functionality*/ 
      child_func(pipe_fd, cmd); 
     } 
     else 
     { 
      /*Parent functionality*/ 
      cmd_output_len = parent_fun(pid, pipe_fd); 
     } 
    } 
    return ret_value; 
} 

int child_func(int pipe_fd[], const char * cmd) 
{ 
    int status = 5; 
    int read_fd = pipe_fd[0];  /*read file descriptor*/ 
    int write_fd = pipe_fd[1];  /*write file descriptor*/ 

    int exit_status = 0; 

    /*close read fd*/ 
    close(read_fd); 

    /*dup2 stdout to write fd*/ 
    //status = dup2(1, write_fd); 
    status = dup2(write_fd, 1); 
    if(status<0) 
    { 
     exit(-1); 
    } 
    else 
    { 
     system(cmd); 
     exit(0); 
    } 
} 


int parent_fun(int child_id, int pipe_fd[]) 
{ 
    int status = -1; 
    int len = 0; 
    bool_e break_loop = FALSE; 
    int read_fd = pipe_fd[0];  /*read file descriptor*/ 
    int write_fd = pipe_fd[1];  /*write file descriptor*/ 

    /*close write fd*/ 
    close(write_fd); 

    while(1) 
    { 
     sleep(1); 
     status = waitpid(child_id, &status, WNOHANG); 
     switch(status) 
     { 
      case 0: 
        /*Child is still active*/ 
        printf("No process waiting to exit..\n"); 
        len = do_ur_fun(read_fd); 
        write(1, output, len); 
       break; 
      /*case EINTR: 
      case ECHILD: 
      case EINVAL: 
        perror("waitpid error"); 
        break_loop = TRUE; 
       break;*/ 
      default: 
       if(status<0) 
       { 
        perror("waitpid error"); 
        break_loop = TRUE; 
        len = -1; 
       } 
       else if(child_id == status) 
       { 
        /*Valid staus from child*/ 
        len = read_output(read_fd, output); 
        //write(1, output, len); 
        break_loop = TRUE; 
       } 
       else 
       { 
       } 
       break; 
     } 
     if(TRUE == break_loop) 
     { 
      break; 
     } 
    } 
    return len; 
} 




int do_ur_fun (int read_fd) 
{ 
     /*Do your exec*/ 
} 
1

MaheshGupta024在您的代碼中發現了一個非常重要的問題;我假設你會解決這個問題。

一個其他的問題領域是:

close(1); 
if (dup2(pipefd[0], 0)==-1) 
    perror("Can't redirect stdin"); 
close(pipefd[1]); 

for (i=1; i< argc; i++){ 
    if ((wait(NULL))== -1) 
     perror("Wait error"); 

    while ((c= read(pipefd[0], readin, SIZE)) > 0){; 
     //print buf count 
     total += atoi(readin); 
    } 
} 

第一關關閉進程的標準輸出;這很少是一個好主意。下一行將管道的讀取端複製到標準輸入 - 這很好。如上面評論所述,perror()不會退出。然後關閉管道的寫入端 - 這是正確的;但是你應該大概關閉管道的讀取端,因爲你已經將它設置爲來自管道。

你的循環開始確定;在wait()行中有多餘的括號。您可以從pipefd[0]而不是標準輸入讀取 - 所以也許你不想關閉pipefd [0],但也沒有你需要將它複製到標準輸入。那麼你有一個嵌套的循環,關於管道讀取數據,同時還有從孩子讀更多的數據 - 你不絕對需要wait()代碼其循環自內而不會終止,直到所有的孩子都死了。另一方面,它沒有太大的傷害 - 在第一個孩子死後,你會讀取所有其他孩子的數據,然後進入外部循環並等待其他孩子,內部循環立即終止沒有數據可供閱讀。

所以:

  • 不要關閉標準輸出。
  • 不要DUP讀取標準輸入管道。
  • 決定是否要清理循環 - 它會工作,但可能更乾淨。

run()函數爲:

void run(char *f){ 
    int fp; 
    if ((fp= open(f, O_RDONLY)) == -1) 
     perror("Can't open the file"); 

    close(pipefd[0]); 
    dup2(pipefd[1], 1); 
    close(pipefd[1]); 
    execlp("ls1", f, NULL); 
} 

的參數應該是const char *f(或使用namefile代替f)。我還會將pipefd數組傳遞給該函數,而不是使用全局變量 。 不要調用文件描述符fp;該名稱通常表示FILE *類型的變量,而不是int。 但是,您不需要首先打開文件 - 除非您希望調用程序執行錯誤報告而不是調用的程序。但是,如果您確實希望調用程序執行錯誤報告,則應在繼續之前關閉文件描述符。 (我已經評論過perror()返回)。

execlp()之後打印錯誤消息是個好主意;函數返回的唯一時間是失敗時,所以不需要測試它的返回值。您可能也想退出 - 而不是在致電run()之後讓失敗的功能通過主程序的其餘部分。

好處:您確實關閉了兩個管道文件描述符。

因此:

void run(const char *file, int *pipefd) 
{ 
    close(pipefd[0]); 
    dup2(pipefd[1], 1); 
    close(pipefd[1]); 
    execlp("ls1", f, NULL); 
    perror("Failed to exec ls1"); 
    exit(EXIT_FAILURE); 
}