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

PoV*_*oVa 2 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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

stuff to be read
Run Code Online (Sandbox Code Playgroud)

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

./a.out
test
Can read
Bytes read: 5
Can't read
Can't read
...
Run Code Online (Sandbox Code Playgroud)

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

cat input | ./a.out # Or ./a.out < input
Bytes read: 0
Can read
Bytes read: 0
Can read
...
Run Code Online (Sandbox Code Playgroud)

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

Som*_*ude 8

问题是poll(就像select)只告诉你对eg的调用read不会阻止.它没有告诉你是否有任何东西要读.

如果你阅读read手册页,你会看到,当它返回0它意味着文件的末尾(或连接关闭套接字).

什么poll是告诉你的是,read可以不受阻塞调用,什么read通过返回告诉你0的是,有没有更多的阅读.

Ctrl-D对于非管道或重定向的输入示例,您可以通过按文件结束快捷键(默认情况下在Linux等POSIX系统上)获得类似的"误报" .