No compro la respuesta previamente aceptada. SIGPIPE
se genera exactamente cuando write
falla con EPIPE
, no de antemano; de hecho, una forma segura de evitar SIGPIPE
sin cambiar las disposiciones globales de la señal es enmascararla temporalmente con pthread_sigmask
, realizar el write
, luego realizar sigtimedwait
(con tiempo de espera cero) para consumir cualquier SIGPIPE
señal pendiente (que se envía a el hilo de llamada, no el proceso) antes de desenmascararlo nuevamente.
Creo que la razón por la que SIGPIPE
existe es mucho más simple: establecer un comportamiento sano por defecto para programas puros de "filtro" que continuamente leen la entrada, la transforman de alguna manera y escriben la salida. Sin ellos SIGPIPE
, a menos que estos programas manejen explícitamente los errores de escritura y salgan inmediatamente (que podría no ser el comportamiento deseado para todos los errores de escritura, de todos modos), continuarán ejecutándose hasta que se queden sin entrada incluso si su tubería de salida se ha cerrado. Seguro que puede duplicar el comportamiento de SIGPIPE
comprobando explícitamente EPIPE
y saliendo, pero el propósito principal SIGPIPE
era lograr este comportamiento de forma predeterminada cuando el programador es vago.
write
.Porque su programa puede estar esperando E / S o suspendido. Un SIGPIPE interrumpe su programa de forma asincrónica, terminando la llamada al sistema y, por lo tanto, puede manejarse de inmediato.
Actualizar
Considere una tubería
A | B | C
.Para ser precisos, asumiremos que B es el ciclo de copia canónico:
B
está bloqueado en la llamada read (2) en espera de datos desde elA
momento en queC
finaliza. Si espera el código de retorno de write (2) , ¿cuándo lo verá B? La respuesta, por supuesto, no es hasta que A escriba más datos (lo que podría ser una larga espera, ¿qué pasa si A está bloqueado por otra cosa?). Observe, por cierto, que esto también nos permite un programa más simple y limpio. Si dependía del código de error de escritura, necesitaría algo como:Otra actualización
Ajá, estás confundido sobre el comportamiento de la escritura. Verá, cuando el descriptor de archivo con la escritura pendiente se cierra, el SIGPIPE ocurre en ese momento. Si bien la escritura devolverá -1 eventualmente , el objetivo de la señal es notificarle de forma asincrónica que la escritura ya no es posible. Esto es parte de lo que hace que toda la elegante estructura de co-rutina de las tuberías funcione en UNIX.
Ahora, podría señalarle una discusión completa en cualquiera de los varios libros de programación del sistema UNIX, pero hay una mejor respuesta: puede verificarlo usted mismo. Escriba un
B
programa simple [1] - ya tiene las agallas, todo lo que necesita es unmain
y algunos incluyen - y agregue un controlador de señal paraSIGPIPE
. Ejecutar una tubería comoy en otra ventana de terminal, adjunte un depurador a B y coloque un punto de interrupción dentro del manejador de señal B.
Ahora, mata más y B debería entrar en tu manejador de señales. examine la pila. Verá que la lectura aún está pendiente. deje que el manejador de señales proceda y regrese, y observe el resultado devuelto por write , que luego será -1.
[1] Naturalmente, escribirás tu programa B en C. :-)
fuente
SIGPIPE
se no entregados durante la lectura, pero durante elwrite
. No necesita escribir un programa en C para probarlo, simplemente ejecútelocat | head
ypkill head
en una terminal separada. Verá quecat
felizmente vive esperando en su, soloread()
cuando escribe algo y presiona enter,cat
muere con una tubería rota, exactamente porque intentó escribir la salida.SIGPIPE
no se puede entregarB
mientrasB
está bloqueadoread
porqueSIGPIPE
no se genera hasta que seB
intenta elwrite
. Ningún subproceso puede "estar esperando E / S o suspendido de otra manera" mientras se llamawrite
al mismo tiempo.SIGPIPE
está levantando mientras está bloqueado en unread
? No puedo reproducir ese comportamiento en absoluto (y en realidad no estoy seguro de por qué acepté esto en primer lugar)https://www.gnu.org/software/libc/manual/html_mono/libc.html
Este enlace dice:
Un tubo o FIFO debe estar abierto en ambos extremos simultáneamente. Si lee de un archivo de tubería o FIFO que no tiene ningún proceso que escriba en él (quizás porque todos han cerrado el archivo o salido), la lectura devuelve el final del archivo. Escribir en una tubería o FIFO que no tiene un proceso de lectura se trata como una condición de error; genera una señal SIGPIPE y falla con el código de error EPIPE si la señal se maneja o bloquea.
- Macro: int SIGPIPE
Tuberia rota. Si usa tuberías o FIFO, debe diseñar su aplicación para que un proceso abra la tubería para lectura antes de que otro comience a escribir. Si el proceso de lectura nunca comienza o termina inesperadamente, al escribir en la tubería o FIFO se genera una señal SIGPIPE. Si SIGPIPE se bloquea, maneja o ignora, la llamada infractora falla con EPIPE en su lugar.
Los archivos especiales Pipes y FIFO se tratan con más detalle en Pipes y FIFO.
fuente
Creo que es para conseguir que el manejo de errores sea correcto sin requerir mucho código en todo lo que se escribe en una tubería.
Algunos programas ignoran el valor de retorno de
write()
; sinSIGPIPE
ellos generarían inútilmente toda la producción.Los programas que comprueban el valor de retorno
write()
probablemente impriman un mensaje de error si falla; esto es inapropiado para una tubería rota, ya que en realidad no es un error para toda la tubería.fuente
Información de la máquina:
Linux 3.2.0-53-generic # 81-Ubuntu SMP Jue 22 Ago 21:01:03 UTC 2013 x86_64 x86_64 x86_64 GNU / Linux
gcc versión 4.6.3 (Ubuntu / Linaro 4.6.3-1ubuntu5)
Escribí este código a continuación:
Salida:
Puede ver que en todos los casos
SIGPIPE
solo se recibe después de que el proceso de escritura (se intenta escribir) más de 3 caracteres.¿No prueba esto que
SIGPIPE
no se genera inmediatamente después de que termina el proceso de lectura, sino después de un intento de escribir algunos datos más en una tubería cerrada?fuente