轮询管道后fgetc仍然阻塞

时间:2017-09-28 01:26:31

标签: c pipe polling fgetc

目前,我正在阅读来自execlp的儿童计划的输入行。所以基本上,如果一个子程序无法正常执行,它在读取时不应该是管道信息,并且会抛出错误。

我尝试轮询文件描述符,无论程序是否正确执行,它都返回一个。所以基本上我得到了民意调查,然后fgetc挂起/阻塞,因为没有什么可读,但fgetc也没有返回-1。

阅读和投票:

char* read_line(int fd) {
    // fd is a pipe's read end. I know it reads properly.
    FILE *file = fdopen(fd, "r"); 
    int ret;
    struct pollfd fdinfo[1];
    fdinfo[0].fd = fd;
    fdinfo[0].events = POLLIN;
    ret = poll(fdinfo,1, 1000);
    if (ret < 0) {
        return "NOPE";
    }   
    char* result = malloc(sizeof(char) * 80);
    memset(result, 0, sizeof(int));
    int position = 0;
    int next = 0;
    while (1) {
        next = fgetc(file); //STALLING HERE
        if (next == '!') {
                free(result);
                return "!";
        }
        if (next == EOF || next == '\n') {
            result[position] = '\0';
            return result;
        } else {
            result[position++] = (char)next;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您没有充分检查poll()提供给您的信息。您确实检测到poll()通过返回-1报告错误的情况,但它不会保证有任何数据可供读取。否定返回值表示poll()未能完成其工作;它没有告诉你任何轮询文件描述符的状态。

首先,poll()如果超时则返回0。在这种情况下,您的代码只是向前滚动并尝试从文件描述符中读取,除非数据恰好在poll()的返回和fgetc()的调用之间到达,否则将阻止该文件描述符。

在第二位,poll()通过设置一个或多个相应的revent位并在该FD上报告事件(部分通过返回正数)来指示指定文件描述符的问题)。具体地,

  如果条件为真,

poll()会在revents中设置POLLHUP,POLLERR和POLLNVAL标志, 即使应用程序未在事件中设置相应的位

  

正[返回]值表示pollfd成员非零的revents个结构[...]的总数

POSIX 1003.1-2008;重点补充)

如果写入管道另一端的子进程崩溃,您可能会看到POLLHUP事件。如果您的程序以某种方式搞砸了文件描述符处理,您可能会看到POLLNVAL事件,并且您始终必须考虑到I / O错误的可能性,poll()发出POLLERR事件的信号。

因此,为避免阻塞,只有当poll()返回1并且在文件中的事件中发出POLLIN信号时,才应尝试从管道读取。可以想象,您可能会看到POLLERR或POLLHUP。如果有任何POLLERR,我建议中止,但是当管道的写入端在任何进程中不再打开时,可以预期POLLHUP,并且这不会使任何可能仍然可用的数据无效(这将是由陪同的POLLIN发出信号。