Это ожидаемое поведение, потому что регистр конца ввода приводит к тому, что read()
не блокируется;он немедленно возвращает 0.
Если вы посмотрите на man 2 select , это ясно говорит о том, что дескриптор в readfds
установлен, если read()
в этом дескрипторе не будет блокироваться (привремя вызова select()
).
Если вы использовали poll()
, он также немедленно возвратился бы с POLLHUP
в revents
.
Как отмечает OP, правильным обходным решением является повторное открытие FIFO.
Поскольку ядро Linux поддерживает ровно один объект внутреннего канала для представления каждого открытого FIFO (см. man 7 fifo и man 7 pipe ), надежный подход в Linux состоит в том, чтобы открывать другой дескриптор для FIFO всякий раз, когда встречается конец ввода (read()
возвращает 0), и закрывать оригинал.В то время, когда открыты оба дескриптора , , они ссылаются на один и тот же объект канала ядра, поэтому нет гоночного окна или риска потери данных.
В псевдо-C:
fifoflags = O_RDONLY | O_NONBLOCK;
fifofd = open(fifoname, fifoflags);
if (fifofd == -1) {
/* Error checking */
}
/* ... */
/* select() readfds contains fifofd, or
poll() returns POLLIN for fifofd: */
n = read(fifofd, buffer, sizeof buffer)
if (!n) {
int tempfd;
tempfd = open(fifopath, fifoflags);
if (tempfd == -1) {
const int cause = errno;
close(fifofd);
/* Error handling */
}
close(fifofd);
fifofd = tempfd;
/* A writer has closed the FIFO. */
} else
/* Handling for the other read() result cases */
Политика выделения файловых дескрипторов в Linux такова, что tempfd
будет бесплатным дескриптором с наименьшим номером.
В моей системе (ноутбук Core i5-7200U), повторно открыв FIFO в этомпуть занимает не более 1,5 мкс.То есть это может быть сделано около 680 000 раз в секунду.Я не думаю, что это открытие является узким местом для любого разумного сценария, даже на маломощных встроенных машинах Linux.