Aparte del problema de "demasiadas señales", las señales pueden ignorarse explícitamente. Desde man 2 signal
:
If the signal signum is delivered to the process, then one of the
following happens:
* If the disposition is set to SIG_IGN, then the signal is ignored.
Las señales también se pueden bloquear. Desde man 7 signal
;
A signal may be blocked, which means that it will not be delivered
until it is later unblocked. Between the time when it is generated
and when it is delivered a signal is said to be pending.
Tanto los conjuntos de señales bloqueados como los ignorados son heredados por los procesos secundarios, por lo que puede ocurrir que el proceso principal de su aplicación ignore o bloquee una de estas señales.
¿Qué sucede cuando se entregan múltiples señales antes de que el proceso haya terminado de manejar las anteriores? Eso depende del sistema operativo. El signal(2)
La página de manual vinculada anteriormente lo analiza:
- El Sistema V restablecería la disposición de la señal al valor predeterminado. Peor aún, la entrega rápida de múltiples señales daría como resultado llamadas recursivas (?).
- BSD bloquearía automáticamente la señal hasta que termine el controlador.
- En Linux, esto depende de los indicadores de compilación establecidos para GNU
libc
, pero esperaría el comportamiento de BSD.
No puede confiar en que todas las señales enviadas serán entregadas. Por ejemplo, el kernel de Linux "fusiona" SIGCHLD si un proceso tarda mucho tiempo en manejar SIGCHLD desde un proceso secundario cerrado.
Para responder otra parte de su pregunta, las señales se "ponen en cola" dentro del núcleo si llegan varias señales diferentes en un intervalo demasiado corto.
Deberías usar sigaction()
para configurar el controlador de señal con el sa_sigaction
miembro de siginfo_t
, configurando el sa_mask
miembro del siginfo_t
argumento cuidadosamente. Creo que esto significa enmascarar al menos todas las señales "asincrónicas". Según la página de manual de Linux sigaction()
, también enmascarará la señal que se está manejando. Creo que deberías establecer el sa_flags
miembro de SA_SIGINFO, pero no recuerdo por qué tengo esta superstición. Creo que esto hará que su proceso sea un controlador de señales que permanezca establecido sin condiciones de carrera y que no sea interrumpido por la mayoría de las otras señales.
Escriba su función de controlador de señales con mucho, mucho cuidado. Básicamente, simplemente configure una variable global para indicar que se captó una señal y haga que el resto del proceso se ocupe de la acción deseada para esa señal. Las señales se enmascararán durante la menor cantidad de tiempo de esa manera.
Además, querrá probar su código de manejo de señales muy a fondo. Póngalo en un pequeño proceso de prueba y envíe tantas señales SIGUSR1 y SIGUSR2 como sea posible, tal vez desde 2 o 3 programas de envío de señales de propósito especial. Mezcle algunas otras señales también, una vez que esté seguro de que su código puede manejar SIGUSR1 y SIGUSR2 de manera rápida y correcta. Prepárese para una depuración difícil.
Si está usando Linux y solo Linux, podría pensar en usar signalfd()
para crear un descriptor de archivo que puede select()
o encuesta para recibir esas señales. Usando signalfd()
podría facilitar la depuración.
Se garantiza que se entregará una señal, en el sentido de que si un proceso llama con éxito a kill
, entonces el objetivo recibirá la señal. Esto es asíncrono:el remitente no tiene forma de saber cuándo se recibe o procesa la señal. Sin embargo, esto no garantiza que se entregue la señal. El objetivo podría morir antes de que pueda procesar la señal. Si el objetivo ignora la señal en el momento en que se envía, la señal no tendrá efecto. Si el objetivo recibe varias instancias del mismo número de señal antes de que pueda procesarlas, las señales pueden fusionarse (y generalmente lo hacen):si envía la misma señal dos veces a un proceso, no puede saber si el proceso recibirá la señal una o dos veces. Las señales están diseñadas principalmente para matar un proceso o como una forma de hacer que un proceso preste atención, no están diseñadas para la comunicación como tal.
Si necesita una entrega confiable, entonces necesita un mecanismo de comunicación diferente. Hay dos mecanismos principales de comunicación entre procesos:una tubería permite la comunicación unidireccional; un socket permite la comunicación bidireccional y múltiples conexiones al mismo servidor. Si necesita que el destino procese tantas notificaciones como las que envía, envíe bytes a través de una canalización.