手动输入时,轮询在stdin上起作用,但在输入是管道输入而不是重定向时则不起作用

时间:2017-11-22 07:54:59

标签: c linux shell polling

考虑这个C程序:

#include <poll.h>
#include <stdio.h>
#include <unistd.h>

#define TIMEOUT 500 // 0.5 s
#define BUF_SIZE 512

int fd_can_read(int fd, int timeout) {
    struct pollfd pfd;

    pfd.fd = fd;
    pfd.events = POLLIN;

    if (poll(&pfd, 1, timeout)) {
        if (pfd.revents & POLLIN) {
            return 1;
        }
    }

    return 0;
}

int main(int argv, char **argc) {
    int fd;
    size_t bytes_read;
    char buffer[BUF_SIZE];

    fd = STDIN_FILENO;

    while (1) {
        if (fd_can_read(fd, TIMEOUT)) {
            printf("Can read\n");
            bytes_read = read(fd, buffer, sizeof(buffer));

            printf("Bytes read: %zu\n", bytes_read);
        }
        else {
            printf("Can't read\n");
        }
    }
}

它尝试轮询给定的文件描述符(在这种情况下是stdin的fd),并尝试在可用于读取时读取它。这是一个名为“input”的示例输入文件:

stuff to be read

所以,让我说我运行程序,提供一些输入并关闭它:

./a.out
test
Can read
Bytes read: 5
Can't read
Can't read
...

因此,让我们尝试通过将其内容管道/重定向到我的程序的stdin来读取文件中的输入:

cat input | ./a.out # Or ./a.out < input
Bytes read: 0
Can read
Bytes read: 0
Can read
...

现在,轮询立即返回(不等待超时用完),并给出我没想到的结果。我知道poll()无法正确处理文件,但如果我没弄错,我就不会从文件中读取文件。

1 个答案:

答案 0 :(得分:8)

问题在于poll(就像select)只会告诉您对... read不会阻止。它没有告诉你是否有任何东西可以阅读。

如果您阅读the read manual page,您会看到当它返回0时,它意味着文件结尾(或者套接字连接已关闭)。

poll告诉您的是,read可以不受阻挡地调用,read通过返回0告诉您的是,没有其他内容可供阅读。

你会得到一个类似的假阳性&#34;通过按下非管道或重定向输入示例的文件结尾快捷键(默认情况下,在Linux上的POSIX系统上 Ctrl-D )。