Úselo a sigaction()
menos que tenga razones muy convincentes para no hacerlo.
La signal()
interfaz tiene antigüedad (y por lo tanto disponibilidad) a su favor, y se define en el estándar C. Sin embargo, tiene una serie de características indeseables que se sigaction()
evitan, a menos que use las marcas agregadas explícitamente sigaction()
para permitirle simular fielmente el signal()
comportamiento anterior.
- La
signal()
función no (necesariamente) bloquea la llegada de otras señales mientras se ejecuta el controlador actual; sigaction()
puede bloquear otras señales hasta que regrese el controlador actual.
- La
signal()
función (generalmente) restablece la acción de la señal a SIG_DFL
(predeterminada) para casi todas las señales. Esto significa que el signal()
controlador debe reinstalarse como su primera acción. También abre una ventana de vulnerabilidad entre el momento en que se detecta la señal y se reinstala el controlador durante el cual, si llega una segunda instancia de la señal, se produce el comportamiento predeterminado (generalmente termina, a veces con prejuicio, también conocido como volcado del núcleo).
- El comportamiento exacto de
signal()
varía entre sistemas, y los estándares permiten esas variaciones.
Estas son generalmente buenas razones para usar en sigaction()
lugar de signal()
. Sin embargo, la interfaz de sigaction()
es innegablemente más complicada.
Cualquiera de los dos que utiliza, no se deje tentar por las interfaces de señal alternativos tales como
sighold()
,
sigignore()
,
sigpause()
y
sigrelse()
. Son nominalmente alternativas a sigaction()
, pero apenas están estandarizadas y están presentes en POSIX por compatibilidad con versiones anteriores en lugar de uso serio. Tenga en cuenta que el estándar POSIX dice que su comportamiento en programas de subprocesos múltiples no está definido.
Los programas y señales de subprocesos múltiples son otra historia complicada. AFAIK, ambos signal()
y sigaction()
están bien en aplicaciones de subprocesos múltiples.
Cornstalks observa :
La página de manual de Linux signal()
dice:
Los efectos de signal()
en un proceso de subprocesos múltiples no están especificados.
Por lo tanto, creo que sigaction()
es lo único que se puede usar de forma segura en un proceso de subprocesos múltiples.
Eso es interesante. La página del manual de Linux es más restrictiva que POSIX en este caso. POSIX especifica para signal()
:
Si el proceso es de subprocesos múltiples, o si el proceso es de subprocesos simples y se ejecuta un controlador de señal que no sea como resultado de:
- El llamado proceso
abort()
, raise()
, kill()
, pthread_kill()
, o sigqueue()
para generar una señal de que no está bloqueado
- Una señal pendiente se desbloquea y se entrega antes de que vuelva la llamada que la desbloqueó
el comportamiento no está definido si el controlador de señal se refiere a cualquier objeto que no sea errno
con una duración de almacenamiento estático que no sea mediante la asignación de un valor a un objeto declarado como volatile sig_atomic_t
, o si el controlador de señal llama a cualquier función definida en este estándar que no sea una de las funciones enumeradas en Conceptos de señal .
Por lo tanto, POSIX especifica claramente el comportamiento de signal()
una aplicación multiproceso.
Sin embargo, sigaction()
es preferible en prácticamente todas las circunstancias, y el código portátil de subprocesos múltiples debería usarse a sigaction()
menos que haya una razón abrumadora por la que no puede hacerlo (como "solo usar funciones definidas por el Estándar C") y sí, el código C11 puede ser múltiple roscado). Que es básicamente lo que también dice el párrafo inicial de esta respuesta.
signal
es en realidad del comportamiento de Unix System V. POSIX permite este comportamiento o el comportamiento BSD mucho más sensato, pero como no puede estar seguro de cuál obtendrá, es mejor usarlosigaction
.SA_RESETHAND
, tambiénSA_NODEFER
.sigaction()
, entonces está esencialmente obligado a usar la especificación Estándar C parasignal()
. Sin embargo, eso le brinda un conjunto de opciones extremadamente empobrecido para lo que puede hacer. Puede: modificar (alcance del archivo) variables de tipovolatile sig_atomic_t
; llame a una de las funciones de 'salida rápida' (_Exit()
,quick_exit()
) oabort()
; llamarsignal()
con el número de señal actual como argumento de señal; regreso. Y eso es. No se garantiza que cualquier otra cosa sea portátil. Eso es tan estricto que la mayoría de la gente ignora esas reglas, pero el código resultante es dudoso.sigaction()
demostración de los propios GCC: gnu.org/software/libc/manual/html_node/… ; y excelentesignal()
demostración de los propios GCC: gnu.org/software/libc/manual/html_node/… . Tenga en cuenta que en lasignal
demostración evitan cambiar el controlador de ignore (SIG_IGN
) si eso es lo que se configuró previamente intencionalmente.Para mí, esta línea de abajo fue suficiente para decidir:
http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07
Ya sea que esté comenzando desde cero o modificando un programa antiguo, sigaction debería ser la opción correcta.
fuente
Son diferentes interfaces para las instalaciones de señal del sistema operativo. Uno debería preferir usar sigaction para señalar si es posible ya que la señal () tiene un comportamiento definido por la implementación (a menudo propenso a la carrera) y se comporta de manera diferente en Windows, OS X, Linux y otros sistemas UNIX.
Consulte esta nota de seguridad para más detalles.
fuente
la señal () es estándar C, sigaction () no lo es.
Si puede usar cualquiera de los dos (es decir, está en un sistema POSIX), use sigaction (); no se especifica si signal () restablece el controlador, lo que significa que para ser portátil debe llamar a signal () nuevamente dentro del controlador. Lo que es peor es que hay una carrera: si obtienes dos señales en rápida sucesión y la segunda se entrega antes de reinstalar el controlador, tendrás la acción predeterminada, que probablemente va a matar tu proceso. sigaction () , por otro lado, está garantizado para usar semántica de señal "confiable". No necesita reinstalar el controlador, ya que nunca se restablecerá. Con SA_RESTART, también puede obtener algunas llamadas del sistema para reiniciar automáticamente (por lo que no tiene que verificar manualmente si hay EINTR). sigaction () tiene más opciones y es confiable, por lo que se recomienda su uso.
Psst ... no le digas a nadie que te dije esto, pero POSIX actualmente tiene una función bsd_signal () que actúa como señal () pero proporciona semántica BSD, lo que significa que es confiable. Su uso principal es para portar aplicaciones antiguas que asumían señales confiables, y POSIX no recomienda su uso.
fuente
bsd_signal()
: algunas implementaciones de POSIX pueden tener la función, pero POSIX en sí no contiene dicha función (consulte POSIX ).En breve:
sigaction()
es bueno y está bien definido, pero es una función de Linux y, por lo tanto, solo funciona en Linux.signal()
es malo y está mal definido, pero es una función estándar de C y, por lo tanto, funciona en cualquier cosa.¿Qué tienen que decir las páginas de manual de Linux al respecto?
man 2 signal
(Véalo en línea aquí ) declara:En otras palabras: no usar
signal()
. Use en susigaction()
lugar!¿Qué piensa el CCG?
Fuente: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
Entonces, si tanto Linux como GCC dicen no usar
signal()
, sino usarsigaction()
en su lugar, eso plantea la pregunta: ¿cómo diablos usamos estasigaction()
cosa confusa ?Ejemplos de uso:
Lea el EXCELENTE
signal()
ejemplo de GCC aquí: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-HandlingY su EXCELENTE
sigaction()
ejemplo aquí: https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.htmlDespués de leer esas páginas, se me ocurrió la siguiente técnica para
sigaction()
:1.
sigaction()
, ya que es la forma correcta de adjuntar un controlador de señal, como se describe anteriormente:2. Y
signal()
, aunque no es una buena forma de adjuntar un controlador de señal, como se describió anteriormente, es bueno saber cómo usarlo.Aquí está el código de demostración de GCC copiado y pegado, ya que es tan bueno como va a ser:
Los principales enlaces a tener en cuenta:
signal()
ejemplo oficial de uso de GCC : https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handlingsigaction()
Ejemplo de uso oficial de GCC : https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.htmlsigemptyset()
ysigfillset()
; Todavía no los entiendo exactamente, pero sé que son importantes: https://www.gnu.org/software/libc/manual/html_node/Signal-Sets.htmlVer también:
fuente
Desde la
signal(3)
página del manual:Ambos invocan la misma facilidad subyacente. Presumiblemente no deberías manipular la respuesta de una sola señal con ambas, pero mezclarlas no debería hacer que nada se rompa ...
fuente
También sugeriría usar sigaction () sobre signal () y me gustaría agregar un punto más. sigaction () le ofrece más opciones, como pid del proceso que murió (posible utilizando la estructura siginfo_t).
fuente
Usaría signal () ya que es más portátil, al menos en teoría. Voy a votar a cualquier comentarista que pueda idear un sistema moderno que no tenga una capa de compatibilidad POSIX y admita señal ().
Citando de la documentación GLIBC :
fuente
Desde la señal de la página de manual (7)
Y yo diría que este "problema" existe para la señal (2) y sigaction (2) . Así que ten cuidado con las señales y subprocesos.
... y la señal (2) parece llamar a sigaction (2) debajo en Linux con glibc.
fuente