Je n'achète pas la réponse précédemment acceptée. SIGPIPE
est généré exactement quand le write
échoue avec EPIPE
, pas avant - en fait, un moyen sûr d'éviter SIGPIPE
sans changer les dispositions globales du signal est de le masquer temporairement avec pthread_sigmask
, d'effectuer le write
, puis d'effectuer sigtimedwait
(avec zéro timeout) pour consommer tout en attenteSIGPIPE
signal en (qui est envoyé à le thread appelant, pas le processus) avant de le démasquer à nouveau.
Je crois que la raison SIGPIPE
existe est beaucoup plus simple: établir un comportement par défaut sain pour les programmes de "filtrage" purs qui lisent continuellement l'entrée, la transforment d'une manière ou d'une autre et écrivent la sortie. Sans SIGPIPE
, à moins que ces programmes ne gèrent explicitement les erreurs d'écriture et se terminent immédiatement (ce qui pourrait ne pas être le comportement souhaité pour toutes les erreurs d'écriture, de toute façon), ils continueront de fonctionner jusqu'à ce qu'ils soient à court d'entrée même si leur tube de sortie a été fermé. Bien sûr, vous pouvez dupliquer le comportement de SIGPIPE
en vérifiant explicitement EPIPE
et en quittant, mais le but principal de SIGPIPE
était d'obtenir ce comportement par défaut lorsque le programmeur est paresseux.
write
.Parce que votre programme peut être en attente d'E / S ou suspendu. Un SIGPIPE interrompt votre programme de manière asynchrone, mettant fin à l'appel système, et peut donc être traité immédiatement.
Mettre à jour
Prenons un pipeline
A | B | C
.Juste pour être précis, nous supposerons que B est la boucle de copie canonique:
B
est bloqué sur l' appel read (2) en attente de données à partir deA
quand seC
termine. Si vous attendez le code retour de write (2) , quand B le verra-t-il? La réponse, bien sûr, n'est pas tant que A n'a pas écrit plus de données (ce qui pourrait être une longue attente - et si A était bloqué par autre chose?). Notez, en passant, que cela nous permet également un programme plus simple et plus propre. Si vous dépendiez du code d'erreur de l'écriture, vous auriez besoin de quelque chose comme:Une autre mise à jour
Aha, vous êtes confus sur le comportement de l'écriture. Vous voyez, lorsque le descripteur de fichier avec l'écriture en attente est fermé, le SIGPIPE se produit alors. Alors que l'écriture renverra finalement -1 , le but du signal est de vous avertir de manière asynchrone que l'écriture n'est plus possible. Cela fait partie de ce qui fait que toute la structure élégante de co-routine des tubes fonctionne sous UNIX.
Maintenant, je pourrais vous indiquer toute une discussion dans l'un des nombreux livres de programmation système UNIX, mais il y a une meilleure réponse: vous pouvez le vérifier vous-même. Écrivez un
B
programme simple [1] - vous avez déjà le courage, tout ce dont vous avez besoin est unmain
et quelques inclus - et ajoutez un gestionnaire de signal pourSIGPIPE
. Exécutez un pipeline commeet dans une autre fenêtre de terminal, attachez un débogueur à B et placez un point d'arrêt dans le gestionnaire de signal B.
Maintenant, tuez le plus et B devrait casser votre gestionnaire de signaux. examinez la pile. Vous constaterez que la lecture est toujours en attente. laissez le gestionnaire de signaux continuer et revenir, et regardez le résultat renvoyé par écriture - qui sera alors -1.
[1] Naturellement, vous allez écrire votre programme B en C. :-)
la source
SIGPIPE
n'est pas livré pendant la lecture, mais pendant lewrite
. Vous n'avez pas besoin d'écrire un programme C pour le tester, exécutez simplementcat | head
etpkill head
dans un terminal séparé. Vous verrez quecat
vivre heureux en attendant dans son -read()
seulement lorsque vous tapez quelque chose et appuyez sur Entréecat
meurt avec un tuyau cassé, exactement parce qu'il a essayé d'écrire la sortie.SIGPIPE
ne peut pas être livré àB
whileB
est bloquéread
car ilSIGPIPE
n'est généré que lorsque leB
fichierwrite
. Aucun thread ne peut "être en attente d'E / S ou suspendu d'une autre manière" tout en appelantwrite
en même temps.SIGPIPE
être soulevé alors qu'il est bloqué sur unread
? Je ne peux pas du tout reproduire ce comportement (et je ne sais pas vraiment pourquoi j'ai accepté cela en premier lieu)https://www.gnu.org/software/libc/manual/html_mono/libc.html
Ce lien dit:
Un tuyau ou FIFO doit être ouvert aux deux extrémités simultanément. Si vous lisez à partir d'un tube ou d'un fichier FIFO sur lequel aucun processus n'écrit (peut-être parce qu'ils ont tous fermé le fichier, ou quitté), la lecture renvoie la fin du fichier. L'écriture dans un tube ou un FIFO qui n'a pas de processus de lecture est traitée comme une condition d'erreur; il génère un signal SIGPIPE, et échoue avec le code d'erreur EPIPE si le signal est traité ou bloqué.
- Macro: int SIGPIPE
Tuyau cassé. Si vous utilisez des tubes ou des FIFO, vous devez concevoir votre application de manière à ce qu'un processus ouvre le tube en lecture avant qu'un autre commence à écrire. Si le processus de lecture ne démarre jamais ou se termine de manière inattendue, l' écriture dans le tube ou FIFO déclenche un signal SIGPIPE. Si SIGPIPE est bloqué, traité ou ignoré, l'appel incriminé échoue avec EPIPE à la place.
Les tuyaux et les fichiers spéciaux FIFO sont décrits plus en détail dans Pipes et FIFO.
la source
Je pense que c'est pour que la gestion des erreurs soit correcte sans avoir besoin de beaucoup de code dans tout ce qui écrit dans un tube.
Certains programmes ignorent la valeur de retour de
write()
; sansSIGPIPE
elles, toutes les sorties seraient inutilement générées.Les programmes qui vérifient la valeur de retour de
write()
probablement impriment un message d'erreur en cas d'échec; ceci est inapproprié pour un tuyau cassé car ce n'est pas vraiment une erreur pour l'ensemble du pipeline.la source
Informations sur la machine:
Linux 3.2.0-53-generic # 81-Ubuntu SMP jeu.22 août 21:01:03 UTC 2013 x86_64 x86_64 x86_64 GNU / Linux
gcc version 4.6.3 (Ubuntu / Linaro 4.6.3-1ubuntu5)
J'ai écrit ce code ci-dessous:
Production:
Vous pouvez voir que dans chaque instance
SIGPIPE
n'est reçu qu'après que plus de 3 caractères ont été (essayés d'être) écrits par le processus d'écriture.Cela ne prouve-t-il pas que ce
SIGPIPE
n'est pas généré immédiatement après la fin du processus de lecture, mais après une tentative d'écriture de plus de données dans un tube fermé?la source