Secondo la pagina man di open(2), puoi passare O_RDONLY|O_NONBLOCK
o O_WRONLY|O_NONBLOCK
per evitare il open
syscall da bloccare (otterrai errno == ENXIO
in tal caso)
Come ho commentato, leggi anche le pagine man di fifo(7) e mkfifo(3).
Innanzitutto, alcuni preliminari:
Usando O_NONBLOCK
e poll()
è una pratica comune, non il contrario. Per funzionare correttamente, devi essere sicuro di gestire tutti i poll()
e read()
return indica correttamente:
read()
valore di ritorno di0
significa EOF -- l'altro lato ha chiuso la sua connessione. Questo corrisponde (di solito, ma non su tutti i sistemi operativi) apoll()
restituendo unPOLLHUP
revent. Potresti voler controllarePOLLHUP
prima di tentareread()
, ma non è assolutamente necessario poichéread()
è garantito che restituisca0
dopo che il lato di scrittura si è chiuso.- Se chiami il
read()
prima che uno scrittore si sia connesso e tu haiO_RDONLY | O_NONBLOCK
, otterrai EOF (read()
restituendo0
) ripetutamente, come avrai notato. Tuttavia, se usipoll()
per attendere unPOLLIN
evento prima di chiamareread()
, attenderà che il writer si connetta e non produrrà gli EOF. read()
valore di ritorno-1
di solito significa errore. Tuttavia, seerrno == EAGAIN
, questo significa semplicemente che al momento non ci sono più dati disponibili e che non stai bloccando, quindi puoi tornare apoll()
nel caso in cui sia necessario maneggiare altri dispositivi. Seerrno == EINTR
, quindiread()
è stato interrotto prima di leggere qualsiasi dato e puoi tornare apoll()
o chiama semplicementeread()
di nuovo immediatamente.
Ora, per Linux:
- Se apri dal lato lettura con
O_RDONLY
, quindi:- Il
open()
si bloccherà fino a quando non sarà aperto un writer corrispondente. poll()
darà unPOLLIN
revent quando i dati sono pronti per essere letti o si verifica EOF.read()
si bloccherà fino a quando non viene letto il numero di byte richiesto, la connessione viene chiusa (restituisce 0), viene interrotta da un segnale o si verifica un errore I/O irreversibile. Questo tipo di blocco vanifica lo scopo dell'utilizzo dipoll()
, motivo per cuipoll()
è quasi sempre usato conO_NONBLOCK
. Potresti usare unalarm()
per svegliarsi daread()
dopo un timeout, ma è eccessivamente complicato.- Se lo scrittore chiude, il lettore riceverà un
poll()
POLLHUP
revent eread()
restituirà0
indefinitamente dopo. A questo punto, il lettore deve chiudere il suo filehandle e riaprirlo.
- Il
- Se apri sul lato lettura con
O_RDONLY | O_NONBLOCK
, quindi:- Il
open()
non verrà bloccato. poll()
darà unPOLLIN
revent quando i dati sono pronti per essere letti o si verifica EOF.poll()
si bloccherà anche fino a quando non sarà disponibile un writer, se nessuno è presente.- Dopo che tutti i dati attualmente disponibili sono stati letti,
read()
restituirà -1 e imposteràerrno == EAGAIN
se la connessione è ancora aperta, o restituirà0
se la connessione è chiusa (EOF) o non ancora aperta da un writer . Quandoerrno == EAGAIN
, questo significa che è ora di tornare apoll()
, poiché la connessione è aperta ma non ci sono più dati. Quandoerrno == EINTR
,read()
non ha ancora letto byte ed è stato interrotto da un segnale, quindi può essere riavviato. - Se lo scrittore chiude, il lettore riceverà un
poll()
POLLHUP
revent eread()
restituirà0
indefinitamente dopo. A questo punto il lettore deve chiudere il suo filehandle e riaprirlo.
- Il
- (Specifico per Linux:) Se apri sul lato lettura con
O_RDWR
, quindi:- Il
open()
non verrà bloccato. poll()
darà unPOLLIN
revent quando i dati sono pronti per essere letti. Tuttavia, per le named pipe, EOF non causeràPOLLIN
oPOLLHUP
revents.read()
si bloccherà fino a quando non viene letto il numero di byte richiesto, viene interrotto da un segnale o si verifica qualche altro errore IO fatale. Per le named pipe, non restituiràerrno == EAGAIN
, né restituirà nemmeno0
uno di. Resterà lì finché non viene letto il numero esatto di byte richiesti, o finché non riceve un segnale (nel qual caso restituirà il numero di byte letti fino a quel momento, oppure restituirà -1 e imposteràerrno == EINTR
se finora non sono stati letti byte).- Se il writer si chiude, il reader non perderà la possibilità di leggere la named pipe in un secondo momento se un altro writer apre la named pipe, ma neanche il reader riceverà alcuna notifica.
- Il
- (Specifico per Linux:) Se apri sul lato lettura con
O_RDWR | O_NONBLOCK
, quindi:- Il
open()
non verrà bloccato. poll()
darà unPOLLIN
revent quando i dati sono pronti per essere letti. Tuttavia, EOF non causeràPOLLIN
oPOLLHUP
revent su named pipe.- Dopo che tutti i dati attualmente disponibili sono stati letti,
read()
restituirà-1
e impostaerrno == EAGAIN
. Questo è il momento di tornare apoll()
per attendere altri dati, possibilmente da altri flussi. - Se il writer si chiude, il lettore non perderà la capacità di leggere la named pipe in un secondo momento se un altro writer apre la named pipe. La connessione è permanente.
- Il
Come sei giustamente preoccupato, usando O_RDWR
con pipe non è standard, POSIX o altrove.
Tuttavia, poiché questa domanda sembra sorgere spesso, il modo migliore su Linux per creare "pipe con nome resilienti" che rimangono attive anche quando un lato si chiude e che non causano POLLHUP
revents o restituisce 0
per read()
, consiste nell'usare O_RDWR | O_NONBLOCK
.
Vedo tre modi principali per gestire le named pipe su Linux:
-
(Portatile.) Senza
poll()
, e con una singola pipe:open(pipe, O_RDONLY);
- Ciclo principale:
read()
tutti i dati necessari, possibilmente in loop suread()
chiama.- Se
read() == -1
eerrno == EINTR
,read()
tutto da capo. - Se
read() == 0
, la connessione viene chiusa e tutti i dati sono stati ricevuti.
- Se
-
(Portatile.) Con
poll()
, e con l'aspettativa che le pipe, anche quelle nominate, vengano aperte solo una volta e che, una volta chiuse, debbano essere riaperte sia dal lettore che dallo scrittore, creando una nuova pipeline:open(pipe, O_RDONLY | O_NONBLOCK);
- Ciclo principale:
poll()
perPOLLIN
eventi, possibilmente su più pipe contemporaneamente. (Nota:questo impedisce aread()
dall'ottenere più EOF prima che uno scrittore si sia connesso.)read()
tutti i dati necessari, possibilmente in loop suread()
chiama.- Se
read() == -1
eerrno == EAGAIN
, torna apoll()
passo. - Se
read() == -1
eerrno == EINTR
,read()
tutto da capo. - Se
read() == 0
, la connessione viene chiusa ed è necessario terminare o chiudere e riaprire la pipe.
- Se
-
(Non portatile, specifico per Linux.) Con
poll()
, e con l'aspettativa che le named pipe non terminino mai e possano essere connesse e disconnesse più volte:open(pipe, O_RDWR | O_NONBLOCK);
- Ciclo principale:
poll()
perPOLLIN
eventi, possibilmente su più pipe contemporaneamente.read()
tutti i dati necessari, possibilmente in loop suread()
chiama.- Se
read() == -1
eerrno == EAGAIN
, torna apoll()
passo. - Se
read() == -1
eerrno == EINTR
,read()
tutto da capo. - Se
read() == 0
, qualcosa non va -- non dovrebbe succedere conO_RDWR
su named pipe, ma solo conO_RDONLY
o tubi senza nome; indica un tubo chiuso che deve essere chiuso e riaperto. Se mescoli pipe con nome e senza nome nello stessopoll()
ciclo di gestione degli eventi, potrebbe essere necessario gestire ancora questo caso.
- Se