2016-04-16 45 views
0

基本上我有一個父級進程,它分叉一個孩子並通過管道爲它提供它的標準輸入。子過程可以在兩種情況之一終止:檢查unix管是否關閉而不寫入任何東西?

  • 管道的寫入結束由父關閉,這意味着它達到標準輸入從而接收EOF
  • 的端部或者它接收到一個通過管(在此情況下-1)並退出某些輸入

我的父代碼看起來大致是這樣的:

close(pi[0]); // close input end 
signal(SIGPIPE, SIG_IGN); // do not handle SIGPIPE 
char buffer; 
int ok = 1; 
while(ok && read(STDIN_FILENO, &buffer, 1) > 0) { 
    int b_written = write(pi[1], &buffer, 1); 
    if(b_written == -1) { 
     if(errno == EPIPE) ok = 0; 
     else perror("pipe write"); // some other error 
    } 
} 

正如您所見,我通過檢查errno == EPIPE來檢查管道的讀取端是否已關閉。但是這意味着讀取循環在關閉之前會執行一次額外的迭代。我怎麼可能進行輪詢,以查看管道是否關閉而不必寫入內容?

+1

你目前的處理方式有什麼問題?你可以做什麼來檢查孩子是否還活着,可能會比再做一次write()更昂貴。 – jdarthenay

+0

閱讀'SIGPIPE'。 – fuz

+0

@jdarthenay它可以工作,但是在孩子死後,它會在等待輸入stdin之前再次輸入 – nikitautiu

回答

1

孩子發現信號,如SIGUSR1發現它已經完成。父母可以在接收到SIGUSR1信號時設置一個標誌,並在嘗試讀取輸入之前檢查該標誌。但我不確定SIGUSR1是否在從stdin讀取輸入之前檢查標誌ans後才能收到)。所以我更喜歡使用控制管道,每次孩子知道它將能夠讀取一個數據,並在此控制管道中寫入1。其結果可能是這樣的:

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

#define STOP_VALUE 100 
#define SIZE_STDIN_BUFFER 1024 

static char can_read_more = 1; 

static int handle_child(int *p_child_input_stream, int *p_control_stream) 
{ 
    int pipefd[2][2]; 
    pid_t fk; 

    if (pipe(pipefd[0]) < 0) // Pipe to read input from 
    { 
     perror("pipe"); 
     return -1; 
    } 

    if (pipe(pipefd[1]) < 0) // Pipe to notifiate parent input can be processed 
    { 
     perror("pipe"); 
     close(pipefd[0][0]); 
     close(pipefd[0][1]); 
     return -1; 
    } 

    if ((fk = fork()) < 0) 
    { 
     perror("fork"); 
     close(pipefd[0][0]); 
     close(pipefd[0][1]); 
     close(pipefd[1][0]); 
     close(pipefd[1][1]); 
     return -1; 
    } 

    if (fk == 0) 
    { 
     close(pipefd[0][1]); 
     close(pipefd[1][0]); 
     write(pipefd[1][1], &can_read_more, sizeof(char)); // sizeof(char) == 1 

     ssize_t nb_read = 0; 
     char buffer; 
     while (nb_read >= 0) 
     { 
      nb_read = read(pipefd[0][0], &buffer, sizeof(char)); 
      if (nb_read > 0) 
      { 
       printf("0x%02x\n", (unsigned int) buffer); 
       if (buffer == STOP_VALUE) 
       { 
        nb_read = -1; 
       } 
       else 
       { 
        write(pipefd[1][1], &can_read_more, sizeof(char)); 
       } 
      } 
     } 
     close(pipefd[0][0]); 
     close(pipefd[1][1]); 
     exit(0); 
    } 

    close(pipefd[0][0]); 
    close(pipefd[1][1]); 

    *p_child_input_stream = pipefd[0][1]; 
    *p_control_stream = pipefd[1][0]; 

    return 0; 
} 

int main() 
{ 
    int child_input_stream; 
    int control_stream; 

    if (handle_child(&child_input_stream, &control_stream) < 0) 
    { 
     return 1; 
    } 

    char stdin_buffer[SIZE_STDIN_BUFFER]; 
    char buffer; 
    int ok = 1; 
    int child_available_input = 0; 

    while(ok) 
    { 
     while (child_available_input <= 0 && ok) 
     { 
      ssize_t nb_control = read(control_stream, &buffer, sizeof(char)); 
      if (nb_control > 0) 
      { 
       child_available_input += buffer; 
      } 
      else 
      { 
       fprintf(stderr, "End of child reading its input detected.\n"); 
       ok = 0; 
      } 
     } 

     if (ok) 
     { 
      if (fgets(stdin_buffer, SIZE_STDIN_BUFFER, stdin) == NULL) 
      { 
       ok = 0; 
      } 
      else 
      { 
       if (stdin_buffer[strlen(stdin_buffer) - 1] == '\n') 
       { 
        stdin_buffer[strlen(stdin_buffer) - 1] = '\0'; 
       } 

       char dummy; 
       int input; 
       if (sscanf(stdin_buffer, "%d%c", &input, &dummy) == 1) 
       { 
        buffer = (char) input; 
        write(child_input_stream, &buffer, sizeof(char)); 
        child_available_input--; 
       } 
      } 
     } 
    } 

    return 0; 
}