De acuerdo con la página de manual de open(2), puede pasar O_RDONLY|O_NONBLOCK
o O_WRONLY|O_NONBLOCK
para evitar el open
syscall para ser bloqueado (obtendrá errno == ENXIO
en ese caso)
Como comenté, lea también las páginas man de fifo(7) y mkfifo(3).
Primero, algunos preliminares:
Usando O_NONBLOCK
y poll()
es una práctica común, no al revés. Para trabajar con éxito, debe asegurarse de manejar todos los poll()
y read()
estados de retorno correctamente:
read()
valor de retorno de0
significa EOF -- el otro lado ha cerrado su conexión. Esto corresponde (generalmente, pero no en todos los sistemas operativos) apoll()
devolviendo unPOLLHUP
reventar Es posible que desee verificarPOLLHUP
antes de intentarread()
, pero no es absolutamente necesario ya queread()
está garantizado para devolver0
después de que el lado de escritura se haya cerrado.- Si llama al
read()
antes de que un escritor se haya conectado, y usted tieneO_RDONLY | O_NONBLOCK
, obtendrá EOF (read()
devolviendo0
) repetidamente, como habrás notado. Sin embargo, si usapoll()
esperar unPOLLIN
evento antes de llamarread()
, esperará a que el escritor se conecte y no generará los EOF. read()
valor de retorno-1
generalmente significa error. Sin embargo, sierrno == EAGAIN
, esto simplemente significa que no hay más datos disponibles en este momento y no está bloqueando, por lo que puede volver apoll()
en caso de que otros dispositivos necesiten manipulación. Sierrno == EINTR
, luegoread()
fue interrumpido antes de leer cualquier dato, y puede volver apoll()
o simplemente llama alread()
de nuevo inmediatamente.
Ahora, para Linux:
- Si abre en el lado de lectura con
O_RDONLY
, entonces:- El
open()
bloqueará hasta que haya un escritor correspondiente abierto. poll()
dará unPOLLIN
prevenga cuando los datos estén listos para ser leídos o cuando ocurra EOF.read()
se bloqueará hasta que se lea el número solicitado de bytes, se cierre la conexión (devuelve 0), se interrumpa por una señal o se produzca algún error fatal de E/S. Este tipo de bloqueo anula el propósito de usarpoll()
, por lo quepoll()
casi siempre se usa conO_NONBLOCK
. Podrías usar unalarm()
despertar deread()
después de un tiempo de espera, pero eso es demasiado complicado.- Si el escritor cierra, el lector recibirá un
poll()
POLLHUP
prevención yread()
devolverá0
indefinidamente después. En este punto, el lector debe cerrar su identificador de archivo y volver a abrirlo.
- El
- Si abre en el lado de lectura con
O_RDONLY | O_NONBLOCK
, entonces:- El
open()
no bloqueará. poll()
dará unPOLLIN
prevenga cuando los datos estén listos para ser leídos o cuando ocurra EOF.poll()
también bloqueará hasta que haya un escritor disponible, si no hay ninguno presente.- Después de leer todos los datos disponibles actualmente,
read()
devolverá -1 y estableceráerrno == EAGAIN
si la conexión aún está abierta, o devolverá0
si la conexión está cerrada (EOF) o aún no ha sido abierta por un escritor . Cuandoerrno == EAGAIN
, esto significa que es hora de volver apoll()
, ya que la conexión está abierta pero no hay más datos. Cuandoerrno == EINTR
,read()
aún no ha leído bytes y fue interrumpido por una señal, por lo que puede reiniciarse. - Si el escritor cierra, el lector recibirá un
poll()
POLLHUP
evento, yread()
devolverá0
indefinidamente después. En este punto, el lector debe cerrar su identificador de archivo y volver a abrirlo.
- El
- (Específico de Linux:) Si abre en el lado de lectura con
O_RDWR
, entonces:- El
open()
no bloqueará. poll()
dará unPOLLIN
revent cuando los datos están listos para ser leídos. Sin embargo, para canalizaciones con nombre, EOF no causaráPOLLIN
oPOLLHUP
eventos.read()
se bloqueará hasta que se lea el número solicitado de bytes, se interrumpa por una señal o se produzca algún otro error fatal de E/S. Para canalizaciones con nombre, no devolveráerrno == EAGAIN
, ni siquiera devolverá0
uno de. Simplemente permanecerá allí hasta que se lea el número exacto de bytes solicitados, o hasta que reciba una señal (en cuyo caso devolverá el número de bytes leídos hasta el momento, o devolverá -1 y estableceráerrno == EINTR
si no se leyeron bytes hasta el momento).- Si el escritor se cierra, el lector no perderá la capacidad de leer la canalización con nombre más tarde si otro escritor abre la canalización con nombre, pero el lector tampoco recibirá ninguna notificación.
- El
- (Específico de Linux:) Si abre en el lado de lectura con
O_RDWR | O_NONBLOCK
, entonces:- El
open()
no bloqueará. poll()
dará unPOLLIN
revent cuando los datos están listos para ser leídos. Sin embargo, EOF no causaráPOLLIN
oPOLLHUP
eventos en canalizaciones con nombre.- Después de leer todos los datos disponibles actualmente,
read()
devolverá-1
y establecererrno == EAGAIN
. Este es el momento de volver apoll()
esperar más datos, posiblemente de otros flujos. - Si el escritor se cierra, el lector no perderá la capacidad de leer la canalización con nombre más adelante si otro escritor abre la canalización con nombre. La conexión es persistente.
- El
Como le preocupa, usando O_RDWR
con tuberías no es estándar, POSIX o en otro lugar.
Sin embargo, dado que esta pregunta parece surgir con frecuencia, la mejor manera en Linux de hacer "tuberías con nombre resistentes" que permanezcan vivas incluso cuando un lado se cierra, y que no causen POLLHUP
revents o return 0
para read()
, es usar O_RDWR | O_NONBLOCK
.
Veo tres formas principales de manejar canalizaciones con nombre en Linux:
-
(Portátil.) Sin
poll()
, y con una sola tubería:open(pipe, O_RDONLY);
- Bucle principal:
read()
tantos datos como sea necesario, posiblemente en bucle enread()
llamadas.- Si
read() == -1
yerrno == EINTR
,read()
todo de nuevo. - Si
read() == 0
, la conexión se cierra y se han recibido todos los datos.
- Si
-
(Portátil.) Con
poll()
, y con la expectativa de que las canalizaciones, incluso las con nombre, solo se abran una vez y que, una vez que se cierren, tanto el lector como el escritor deban volver a abrirlas, configurando una nueva canalización:open(pipe, O_RDONLY | O_NONBLOCK);
- Bucle principal:
poll()
paraPOLLIN
eventos, posiblemente en múltiples conductos a la vez. (Nota:esto evita queread()
obtener múltiples EOF antes de que un escritor se haya conectado).read()
tantos datos como sea necesario, posiblemente en bucle enread()
llamadas.- Si
read() == -1
yerrno == EAGAIN
, vuelve apoll()
paso. - Si
read() == -1
yerrno == EINTR
,read()
todo de nuevo. - Si
read() == 0
, la conexión está cerrada y debe terminar o cerrar y volver a abrir la tubería.
- Si
-
(No portátil, específico de Linux). Con
poll()
, y con la expectativa de que las canalizaciones con nombre nunca terminen y se puedan conectar y desconectar varias veces:open(pipe, O_RDWR | O_NONBLOCK);
- Bucle principal:
poll()
paraPOLLIN
eventos, posiblemente en múltiples conductos a la vez.read()
tantos datos como sea necesario, posiblemente en bucle enread()
llamadas.- Si
read() == -1
yerrno == EAGAIN
, vuelve apoll()
paso. - Si
read() == -1
yerrno == EINTR
,read()
todo de nuevo. - Si
read() == 0
, algo anda mal, no debería pasar conO_RDWR
en canalizaciones con nombre, pero solo conO_RDONLY
o tuberías sin nombre; indica una tubería cerrada que debe cerrarse y volverse a abrir. Si mezcla tuberías con nombre y sin nombre en el mismopoll()
ciclo de manejo de eventos, es posible que este caso aún deba manejarse.
- Si