La tubería FIFO siempre se puede leer en select ()

En pseudocódigo C:

while (1) { fifo = open("fifo", O_RDONLY | O_NONBLOCK); fd_set read; FD_SET(fifo, &read); select(nfds, &read, NULL, NULL, NULL); } 

El proceso se suspende cuando se activa con select() hasta que otro proceso se escribe en fifo . Después, siempre encontrará fifo como un descriptor de archivo legible.

¿Cómo evitar este comportamiento (es decir, después de leer fifo una vez, cómo hacer que se encuentre como ilegible hasta que obtenga otra escritura?)

Abrió ese FIFO como solo lectura (O_RDONLY), siempre que no haya un escritor en el FIFO, el final de lectura recibirá un EOF .

La llamada al sistema seleccionado volverá a EOF y por cada EOF que maneje habrá un nuevo EOF . Este es el motivo del comportamiento observado.

Para evitar esto, abra ese FIFO para lectura y escritura (O_RDWR). Esto garantiza que tenga al menos un escritor en el FIFO, por lo que no habrá un EOF y, como resultado, la selección no volverá a menos que alguien escriba en ese FIFO.

La respuesta simple es leer hasta que read() devuelva EWOULDBLOCK (o EAGAIN ), o craps con un error.

Lo que está diciendo simplemente no puede suceder a menos que el sistema operativo (o tiempo de ejecución) que está utilizando tenga errores. De lo contrario debes estar haciendo algo mal. Por ejemplo, select() está usando E / S activada por nivel. Pensaría que, lo más probable, no está agotando el zócalo por completo, por lo que select() siempre indica que le queda algo allí (esto no ocurre con las notificaciones de eventos activados por el borde).

A continuación se muestra un ejemplo simple que muestra cómo se debe leer hasta que read() devuelva EWOULDBLOCK para evitar dejar el descriptor en estado legible (lo he comstackdo y probado en OS X, y casi no hay comprobación de errores, pero debería tener la idea):

 /* * FIFO example using select. * * $ mkfifo /tmp/fifo * $ clang -Wall -o test ./test.c * $ ./test & * $ echo 'hello' > /tmp/fifo * $ echo 'hello world' > /tmp/fifo * $ killall test */ #include  #include  #include  #include  #include  #include  #include  int main() { int fd; int n; fd_set set; ssize_t bytes; size_t total_bytes; char buf[1024]; fd = open("/tmp/fifo", O_RDWR | O_NONBLOCK); if (fd == -1) { perror("open"); return EXIT_FAILURE; } FD_ZERO(&set); FD_SET(fd, &set); for (;;) { n = select(fd+1, &set, NULL, NULL, NULL); if (!n) continue; if (n == -1) { perror("select"); return EXIT_FAILURE; } if (FD_ISSET(fd, &set)) { printf("Descriptor %d is ready.\n", fd); total_bytes = 0; for (;;) { bytes = read(fd, buf, sizeof(buf)); if (bytes > 0) { total_bytes += (size_t)bytes; } else { if (errno == EWOULDBLOCK) { /* Done reading */ printf("done reading (%lu bytes)\n", total_bytes); break; } else { perror("read"); return EXIT_FAILURE; } } } } } return EXIT_SUCCESS; } 

Básicamente, la E / S activada por nivel significa que se le notifica todo el tiempo si hay algo que leer, incluso aunque haya sido notificado de esto antes. Por el contrario, la E / S activada desde el borde significa que se le notificará solo una vez cada vez que lleguen nuevos datos y no importa si la lee o no. select() es una interfaz de E / S activada por nivel.

Espero eso ayude. ¡Buena suerte!