Опрос работает на stdin при вводе вручную, но не при вводе по конвейеру и не перенаправляется

Рассмотрим эту программу на 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");
        }
    }
}

Он пытается опрашивать заданный дескриптор файла (в данном случае это fd stdin) и пытается прочитать его, когда он будет доступен для чтения. Вот пример входного файла с именем "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 ответ

Решение

Проблема в том, что poll (как select) только скажу, что звонок на например read не будет блокировать. Он не говорит вам, есть ли на самом деле что-нибудь для чтения.

И если вы читаете read Страница справочника вы увидите, что когда он вернется 0 это означает конец файла (или соединение закрыто для сокетов).

Какие poll говорит вам, что read можно назвать без блокировки, а что read говорит вам, возвращаясь 0 в том, что больше нечего читать.

Вы получите аналогичное "ложное срабатывание", нажав сочетание клавиш "конец файла" (по умолчанию Ctrl-D в системах POSIX, таких как Linux) для примера ввода без переадресации или с переадресацией.

Другие вопросы по тегам