首页 文章

检查unix管道是否关闭而不写任何东西?

提问于
浏览
0

基本上我有一个父进程,它会分叉一个孩子并通过管道将它作为stdin . 子进程可以在以下两种情况之一中终止:

  • 管道的写入端由父级关闭,这意味着它到达了stdin的末尾,因此接收到 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 来检查管道的读取端是否已关闭 . 但是,这意味着read循环在关闭之前会进行一次额外的迭代 . 我怎么可能轮询看管道是否关闭而不必写一些东西?

1 回答

  • 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;
    }
    

相关问题