2016-04-16 5 views
0

私は基本的に、親プロセスが子プロセスをフォークし、フィードをパイプ経由で受け取ります。子プロセスは、2つのいずれかの場合に終了することができる: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回の余分な繰り返しを行うことを意味します。パイプに何かを書き込まなくてもパイプが閉じられているかどうか調べるにはどうすればいいですか?

+1

現在の取り扱い方法の問題点は何ですか?子供が生きていることを確認するためにできることは、必要以上に 'write()'を行うよりもコストがかかることがあります。 – jdarthenay

+0

'SIGPIPE'を読んでください。 – fuz

+0

@jdarthenayそれは動作しますが、子供が死ぬと、終了する前にstdinの別の入力を待ちます。 – nikitautiu

答えて

1

子供は、完了したことを検出すると、SIGUSR1などの信号を送信する可能性があります。親は、SIGUSR1シグナルを受け取ったときにフラグを設定し、入力を読み取ろうとする前にこのフラグをチェックすることができます。しかし、stdinから入力を読み取る前に、フラグansをチェックした後にSIGUSR1を受信できなかったことを絶対に確信していません。ですから、私はコントロールパイプを使うことを好みます、子供が毎回このコントロールパイプに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; 
} 
関連する問題