Selon la page de manuel open(2), vous pouvez passer O_RDONLY|O_NONBLOCK
ou O_WRONLY|O_NONBLOCK
pour éviter le open
syscall à bloquer (vous obtiendrez errno == ENXIO
dans ce cas)
Comme je l'ai commenté, lisez également les pages de manuel fifo(7) et mkfifo(3).
Tout d'abord, quelques préliminaires :
Utilisation de O_NONBLOCK
et poll()
est une pratique courante - et non l'inverse. Pour travailler avec succès, vous devez être sûr de gérer tous les poll()
et read()
retourner les états correctement :
read()
valeur de retour de0
signifie EOF - l'autre côté a fermé sa connexion. Cela correspond (généralement, mais pas sur tous les OS) àpoll()
renvoyant unPOLLHUP
revent. Vous voudrez peut-être vérifierPOLLHUP
avant de tenterread()
, mais ce n'est pas absolument nécessaire depuisread()
est garanti de retourner0
après la fermeture du côté écriture.- Si vous appelez le
read()
avant qu'un rédacteur ne se soit connecté, et vous avezO_RDONLY | O_NONBLOCK
, vous obtiendrez EOF (read()
retour0
) à plusieurs reprises, comme vous l'avez remarqué. Cependant, si vous utilisezpoll()
attendre unPOLLIN
événement avant d'appelerread()
, il attendra que l'enregistreur se connecte et ne produira pas les EOF. read()
valeur de retour-1
signifie généralement erreur. Cependant, sierrno == EAGAIN
, cela signifie simplement qu'il n'y a plus de données disponibles pour le moment et que vous ne bloquez pas, vous pouvez donc revenir àpoll()
au cas où d'autres appareils auraient besoin d'être manipulés. Sierrno == EINTR
, puisread()
a été interrompu avant la lecture des données, et vous pouvez soit revenir àpoll()
ou appelez simplement leread()
à nouveau immédiatement.
Maintenant, pour Linux :
- Si vous ouvrez côté lecture avec
O_RDONLY
, alors :- Le
open()
bloquera jusqu'à ce qu'un écrivain correspondant soit ouvert. poll()
donnera unPOLLIN
se déclenche lorsque les données sont prêtes à être lues, ou EOF se produit.read()
se bloquera jusqu'à ce que le nombre d'octets demandé soit lu, que la connexion soit fermée (renvoie 0), qu'elle soit interrompue par un signal ou qu'une erreur IO fatale se produise. Ce type de blocage va à l'encontre du but de l'utilisation depoll()
, c'est pourquoipoll()
est presque toujours utilisé avecO_NONBLOCK
. Vous pouvez utiliser unalarm()
se réveiller deread()
après un délai d'attente, mais c'est trop compliqué.- Si le rédacteur se ferme, le lecteur recevra un
poll()
POLLHUP
événement etread()
renverra0
indéfiniment ensuite. À ce stade, le lecteur doit fermer son descripteur de fichier et le rouvrir.
- Le
- Si vous ouvrez côté lecture avec
O_RDONLY | O_NONBLOCK
, alors :- Le
open()
ne bloquera pas. poll()
donnera unPOLLIN
événement lorsque les données sont prêtes à être lues, ou EOF se produit.poll()
bloquera également jusqu'à ce qu'un écrivain soit disponible, s'il n'y en a pas.- Une fois toutes les données actuellement disponibles lues,
read()
renverra -1 et définiraerrno == EAGAIN
si la connexion est toujours ouverte, sinon elle renverra0
si la connexion est fermée (EOF) ou pas encore ouverte par un écrivain . Quanderrno == EAGAIN
, cela signifie qu'il est temps de revenir àpoll()
, puisque la connexion est ouverte mais qu'il n'y a plus de données. Quanderrno == EINTR
,read()
n'a encore lu aucun octet et a été interrompu par un signal, il peut donc être redémarré. - Si le rédacteur se ferme, le lecteur recevra un
poll()
POLLHUP
événement, etread()
renverra0
indéfiniment ensuite. À ce stade, le lecteur doit fermer son descripteur de fichier et le rouvrir.
- Le
- (Spécifique à Linux :) Si vous ouvrez du côté lecture avec
O_RDWR
, alors :- Le
open()
ne bloquera pas. poll()
donnera unPOLLIN
lorsque les données sont prêtes à être lues. Cependant, pour les canaux nommés, EOF ne causera pasPOLLIN
ouPOLLHUP
événements.read()
se bloquera jusqu'à ce que le nombre d'octets demandé soit lu, qu'il soit interrompu par un signal ou qu'une autre erreur IO fatale se produise. Pour les canaux nommés, il ne renverra paserrno == EAGAIN
, il ne renverra même pas0
un des. Il restera là jusqu'à ce que le nombre exact d'octets demandés soit lu, ou jusqu'à ce qu'il reçoive un signal (auquel cas il renverra le nombre d'octets lus jusqu'à présent, ou renverra -1 et définiraerrno == EINTR
si aucun octet n'a été lu jusqu'à présent).- Si le rédacteur se ferme, le lecteur ne perdra pas la possibilité de lire le tube nommé plus tard si un autre rédacteur ouvre le tube nommé, mais le lecteur ne recevra aucune notification non plus.
- Le
- (Spécifique à Linux :) Si vous ouvrez du côté lecture avec
O_RDWR | O_NONBLOCK
, alors :- Le
open()
ne bloquera pas. poll()
donnera unPOLLIN
lorsque les données sont prêtes à être lues. Cependant, EOF ne causera pasPOLLIN
ouPOLLHUP
revents sur les canaux nommés.- Une fois toutes les données actuellement disponibles lues,
read()
renverra-1
et définissezerrno == EAGAIN
. C'est le moment de revenir àpoll()
pour attendre plus de données, éventuellement d'autres flux. - Si l'écrivain se ferme, le lecteur ne perdra pas la possibilité de lire le tube nommé plus tard si un autre écrivain ouvre le tube nommé. La connexion est persistante.
- Le
Comme vous êtes à juste titre concerné, en utilisant O_RDWR
avec des tuyaux n'est pas standard, POSIX ou ailleurs.
Cependant, comme cette question semble revenir souvent, la meilleure façon sous Linux de créer des "canaux nommés résilients" qui restent actifs même lorsqu'un côté se ferme, et qui ne causent pas POLLHUP
renvoie ou retourne 0
pour read()
, est d'utiliser O_RDWR | O_NONBLOCK
.
Je vois trois manières principales de gérer les canaux nommés sous Linux :
-
(Portable.) Sans
poll()
, et avec un seul tube :open(pipe, O_RDONLY);
- Boucle principale :
read()
autant de données que nécessaire, éventuellement en boucle surread()
appels.- Si
read() == -1
eterrno == EINTR
,read()
tout recommencer. - Si
read() == 0
, la connexion est fermée et toutes les données ont été reçues.
- Si
-
(Portable.) Avec
poll()
, et en s'attendant à ce que les canaux, même nommés, ne soient ouverts qu'une seule fois, et qu'une fois fermés, ils doivent être rouverts à la fois par le lecteur et l'auteur, en créant un nouveau pipeline :open(pipe, O_RDONLY | O_NONBLOCK);
- Boucle principale :
poll()
pourPOLLIN
événements, éventuellement sur plusieurs canaux à la fois. (Remarque :Cela empêcheread()
d'obtenir plusieurs EOF avant qu'un écrivain ne se soit connecté.)read()
autant de données que nécessaire, éventuellement en boucle surread()
appels.- Si
read() == -1
eterrno == EAGAIN
, revenir àpoll()
étape. - Si
read() == -1
eterrno == EINTR
,read()
tout recommencer. - Si
read() == 0
, la connexion est fermée et vous devez terminer ou fermer et rouvrir le tuyau.
- Si
-
(Non portable, spécifique à Linux.) Avec
poll()
, et en supposant que les canaux nommés ne se terminent jamais et peuvent être connectés et déconnectés plusieurs fois :open(pipe, O_RDWR | O_NONBLOCK);
- Boucle principale :
poll()
pourPOLLIN
événements, éventuellement sur plusieurs canaux à la fois.read()
autant de données que nécessaire, éventuellement en boucle surread()
appels.- Si
read() == -1
eterrno == EAGAIN
, revenir àpoll()
étape. - Si
read() == -1
eterrno == EINTR
,read()
tout recommencer. - Si
read() == 0
, quelque chose ne va pas -- cela ne devrait pas arriver avecO_RDWR
sur les canaux nommés, mais uniquement avecO_RDONLY
ou tuyaux sans nom ; il indique un tuyau fermé qui doit être fermé et rouvert. Si vous mélangez des canaux nommés et sans nom dans le mêmepoll()
boucle de gestion des événements, ce cas devra peut-être encore être traité.
- Si