¿En qué orden debo enviar señales para cerrar correctamente los procesos?

88

En un comentario sobre esta respuesta de otra pregunta , el comentarista dice:

¡No uses kill -9 a menos que sea absolutamente necesario! SIGKILL no se puede atrapar, por lo que el programa eliminado no puede ejecutar ninguna rutina de apagado para, por ejemplo, borrar archivos temporales. Primero intente HUP (1), luego INT (2), luego SALIR (3)

En principio estoy de acuerdo SIGKILL, pero el resto son novedades para mí. Dado que la señal predeterminada enviada por killes SIGTERM, esperaría que sea la señal más comúnmente esperada para un cierre ordenado de un proceso arbitrario. Además, lo he visto SIGHUPutilizado por razones no terminantes, como decirle a un demonio "vuelva a leer su archivo de configuración". Y me parece que SIGINT(la misma interrupción que obtendría normalmente con Ctrl-C, ¿verdad?) No es tan ampliamente compatible como debería ser, o termina de manera bastante desagradable.

Dado que SIGKILLes un último recurso, ¿qué señales y en qué orden debe enviar a un proceso arbitrario para cerrarlo de la manera más elegante posible?

Si puede, sustente sus respuestas con hechos de apoyo (más allá de las preferencias u opiniones personales) o referencias.

Nota: Estoy particularmente interesado en las mejores prácticas que incluyen la consideración de bash / Cygwin.

Editar: Hasta ahora, nadie parece mencionar INT o QUIT, y hay una mención limitada de HUP. ¿Hay alguna razón para incluirlos en un proceso de matanza ordenado?

PAUSA del sistema
fuente
4
Si tiene que recurrir a SIGKILL para matar realmente un proceso, lo consideraría un error en el programa.
sigjuice

Respuestas:

114

SIGTERM le dice a una aplicación que finalice. Las otras señales le dicen a la aplicación otras cosas que no están relacionadas con el apagado, pero que a veces pueden tener el mismo resultado. No los uses. Si desea que una aplicación se cierre, dígale que lo haga. No le dé señales engañosas.

Algunas personas creen que la forma estándar inteligente de terminar un proceso es enviándole una gran cantidad de señales, como HUP, INT, TERM y finalmente KILL. Esto es ridículo. La señal correcta para la terminación es SIGTERM y si SIGTERM no termina el proceso instantáneamente, como podría preferir, es porque la aplicación ha elegido manejar la señal. Lo que significa que tiene una muy buena razón para no terminar de inmediato: tiene trabajo de limpieza por hacer. Si interrumpe ese trabajo de limpieza con otras señales, no se sabe qué datos de la memoria aún no se han guardado en el disco, qué aplicaciones cliente quedan colgadas o si lo está interrumpiendo "a mitad de frase", lo que efectivamente es corrupción de datos.

Para obtener más información sobre cuál es el significado real de las señales, consulte sigaction (2). No confunda "Acción predeterminada" con "Descripción", no son lo mismo.

SIGINT se utiliza para señalar una "interrupción de teclado" interactiva del proceso. Algunos programas pueden manejar la situación de una manera especial para los usuarios de terminales.

SIGHUP se utiliza para señalar que la terminal ha desaparecido y ya no está mirando el proceso. Eso es todo. Algunos procesos optan por cerrarse en respuesta, generalmente porque su funcionamiento no tiene sentido sin una terminal, algunos optan por hacer otras cosas, como volver a verificar los archivos de configuración.

SIGKILL se usa para eliminar forzosamente el proceso del kernel. Es especial en el sentido de que en realidad no es una señal para el proceso, sino que el kernel lo interpreta directamente.

No envíe SIGKILL. Ciertamente, SIGKILL nunca debería enviarse mediante scripts. Si la aplicación maneja el SIGTERM, la limpieza puede demorar un segundo, puede demorar un minuto, puede demorar una hora . Dependiendo de lo que tenga que hacer la aplicación antes de que esté lista para finalizar. Cualquier lógica que " asume " que la secuencia de limpieza de una aplicación ha tardado lo suficiente y necesita ser atajo o SIGKILL después de X segundos es simplemente errónea .

La única razón por la que una aplicación necesitaría un SIGKILL para terminar es si algo salió mal durante su secuencia de limpieza. En cuyo caso puede abrir una terminal y SIGKILL manualmente. Aparte de eso, la única otra razón por la que SIGKILL algo es porque QUIERES evitar que se limpie solo.

A pesar de que la mitad del mundo envía SIGKILL a ciegas después de 5 segundos, sigue siendo algo terriblemente incorrecto.

lhunath
fuente
13
Tienes razón en que hay mucho mal uso de SIGKILL por ahí. Pero hay un momento y un lugar para usarlo, incluso desde un guión. Muchas, muchas aplicaciones atrapan SIGTERM y salen con gracia en menos de un segundo o en solo unos segundos, y una de ellas todavía se está ejecutando 30 segundos después porque está bloqueada.
dwc
4
@dwc: intente dejar que se ejecute una vez durante una hora. Si no muere, entonces está "encajado" y arreglarlo, o ser perezoso y en el futuro SIGKILL después de algún tiempo. Tenga en cuenta que probablemente esté corrompiendo cosas y recuerde que esto NO es algo que deba hacer "por defecto".
lhunath
2
@lhunath: Espero que no le importe, reorganicé sus párrafos para que la respuesta sea más directa y clara a partir de la pregunta. La perorata anti-SIGKILL es buena, pero un punto secundario. Gracias de nuevo por una respuesta excelente y educativa.
sistema de PAUSA
8
No envíe SIGKILL. Siempre. Simplemente mal. De Verdad? Incluso si su sistema ya se está quemando gracias a los bucles infinitos. Buena suerte. -1
konsolebox
//, votar a favor de Esto es ridículo.
Nathan Basanese
17

Respuesta corta : Enviar SIGTERM, 30 segundos más tarde, SIGKILL. Es decir, envíe SIGTERM, espere un poco (puede variar de un programa a otro, es posible que conozca mejor su sistema, pero de 5 a 30 segundos es suficiente. Al apagar una máquina, es posible que la vea automáticamente esperando hasta 1'30 s). ¿Por qué la prisa, después de todo?), Luego envía SIGKILL.

Respuesta razonable : SIGTERM, SIGINT, SIGKILL Esto es más que suficiente. Es muy probable que el proceso termine antes SIGKILL.

Respuesta larga : SIGTERM, SIGINT, SIGQUIT, SIGABRT,SIGKILL

Esto es innecesario, pero al menos no está engañando el proceso con respecto a su mensaje. Todas estas señales no significan desea que el proceso para detener lo que está haciendo y salir.

No importa qué respuesta elija de esta explicación, ¡téngalo en cuenta!

Si envía una señal que significa otra cosa, el proceso puede manejarla de formas muy diferentes (por un lado). Por otro lado, si el proceso no maneja la señal, no importa lo que envíe después de todo, el proceso se cerrará de todos modos (cuando la acción predeterminada es terminar, por supuesto).

Por lo tanto, debe pensar como programador. ¿Codificaría un controlador de funciones para, digamos, SIGHUPsalir de un programa que se conecta con algo, o lo haría un bucle para intentar conectarse de nuevo? ¡Esa es la pregunta principal aquí! Por eso es importante enviar señales que signifiquen lo que pretendes.

Respuesta larga casi estúpida :

La siguiente tabla contiene las señales relevantes y las acciones predeterminadas en caso de que el programa no las maneje.

Los ordené en el orden que sugiero usar (por cierto, le sugiero que use la respuesta razonable , no esta aquí), si realmente necesita probarlos todos (sería divertido decir que la tabla está ordenada en términos de la destrucción que pueden causar, pero eso no es del todo cierto).

NO se recomiendan las señales con un asterisco (*) . Lo importante de estos es que es posible que nunca sepa para qué está programado. SIGUSR¡ Especialmente ! Puede iniciar el apocalipsis (¡es una señal gratuita para que un programador haga lo que quiera!). Pero, si no se maneja O, en el caso poco probable, se maneja para terminar, el programa terminará.

En la tabla, las señales con opciones predeterminadas para terminar y generar un volcado de memoria se dejan al final, justo antes SIGKILL.

Signal     Value     Action   Comment
----------------------------------------------------------------------
SIGTERM      15       Term    Termination signal
SIGINT        2       Term    Famous CONTROL+C interrupt from keyboard
SIGHUP        1       Term    Disconnected terminal or parent died
SIGPIPE      13       Term    Broken pipe
SIGALRM(*)   14       Term    Timer signal from alarm
SIGUSR2(*)   12       Term    User-defined signal 2
SIGUSR1(*)   10       Term    User-defined signal 1
SIGQUIT       3       Core    CONTRL+\ or quit from keyboard
SIGABRT       6       Core    Abort signal from abort(3)
SIGSEGV      11       Core    Invalid memory reference
SIGILL        4       Core    Illegal Instruction
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal

Entonces sugeriría para esta larga respuesta casi estúpida : SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGQUIT, SIGABRT,SIGKILL

Y finalmente, el

Definitivamente estúpida respuesta larga y larga :

No intentes esto en casa.

SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGALRM, SIGUSR2, SIGUSR1, SIGQUIT, SIGABRT, SIGSEGV, SIGILL, SIGFPEY si nada funcionó, SIGKILL.

SIGUSR2debe probarse antes SIGUSR1porque estamos mejor si el programa no maneja la señal. Y es mucho más probable que maneje SIGUSR1si solo maneja uno de ellos.

Por cierto, el KILL : no está mal enviar SIGKILLa un proceso, como se indicó en otra respuesta. Bueno, piensa en lo que pasa cuando envías un shutdowncomando. Lo intentará SIGTERMy SIGKILLsolo. ¿Por qué cree que es así? ¿Y por qué necesita otras señales, si el mismo shutdowncomando usa solo estas dos?


Ahora, volviendo a la respuesta larga , este es un buen delineador:

for SIG in 15 2 3 6 9 ; do echo $SIG ; echo kill -$SIG $PID || break ; sleep 30 ; done

Duerme 30 segundos entre señales. ¿Por qué más necesitarías un delineador ? ;)

Además, se recomienda: inténtelo solo con señales 15 2 9de la respuesta razonable .

seguridad : retire el segundo echocuando esté listo para comenzar. Yo lo llamo mi dry-runpara los online . Úselo siempre para probar.


Guión killgracefully

En realidad, estaba tan intrigado por esta pregunta que decidí crear un pequeño guión para hacer precisamente eso. Por favor, siéntase libre de descargarlo (clonarlo) aquí:

Enlace de GitHub al repositorio de Killgracefully

DrBeco
fuente
8

Normalmente enviarías SIGTERM, el valor predeterminado de kill. Es el predeterminado por una razón. Solo debe recurrir a él si un programa no se apaga en un período de tiempo razonable SIGKILL. Pero tenga en cuenta que con SIGKILLel programa no hay posibilidad de limpiar las cosas y los datos podrían corromperse.

En cuanto a SIGHUP, HUPsignifica "colgar" e históricamente significaba que el módem se desconectaba. Es esencialmente equivalente a SIGTERM. La razón por la que los demonios a veces usan SIGHUPpara reiniciar o recargar la configuración es que los demonios se separan de cualquier terminal de control ya que un demonio no los necesita y, por lo tanto, nunca los recibiría SIGHUP, por lo que la señal se consideró como "liberada" para uso general. ¡No todos los demonios usan esto para recargar! ¡La acción predeterminada para SIGHUP es terminar y muchos demonios se comportan de esa manera! Por lo tanto, no puede enviar mensajes SIGHUPde correo electrónico a los demonios y esperar que sobrevivan.

Editar: SIGINT probablemente sea inapropiado terminar un proceso, ya que normalmente está vinculado a ^Co cualquiera que sea la configuración del terminal para interrumpir un programa. Muchos programas capturan esto para sus propios fines, por lo que es lo suficientemente común como para que no funcione. SIGQUITnormalmente tiene el valor predeterminado de crear un volcado del núcleo y, a menos que desee archivos del núcleo por ahí, tampoco es un buen candidato.

Resumen: si envía SIGTERMy el programa no muere dentro de su plazo, envíelo SIGKILL.

dwc
fuente
4
Tenga en cuenta que el seguimiento con SIGKILL solo debe realizarse en situaciones en las que el apagado instantáneo sea una prioridad más alta que la prevención de la pérdida o corrupción de datos.
thomasrutter
@dwc No entendí el siguiente punto en su respuesta. ¿Podría ayudarme? "La razón por la que los demonios a veces usan SIGHUP para reiniciar o recargar la configuración es que los demonios se desconectan de cualquier terminal de control y, por lo tanto, nunca recibirían SIGTERM, por lo que la señal se consideró como" liberada "para uso general".
Jack
3
@Jack Déjame intentarlo: SIGHUP es la señal de "colgar" que le dice a un proceso que la terminal se desconectó. Dado que los demonios se ejecutan en segundo plano, no necesitan terminales. Eso significa que una señal de "colgar" no es relevante para los demonios. Nunca lo recibirán de una desconexión de terminal, ya que no tienen terminales conectados en primer lugar. Y dado que la señal está definida de todos modos, aunque no la necesitan para el propósito original, muchos demonios la usan en su lugar para un propósito diferente, como volver a leer sus archivos de configuración.
sistema PAUSA
Gracias sistema PAUSA. esto es útil.
Jack
6

SIGTERMen realidad significa enviar un mensaje a una aplicación: " ¿Sería tan amable de suicidarse? ". Puede ser atrapado y manejado por la aplicación para ejecutar el código de limpieza y apagado.

SIGKILLno puede ser atrapado por aplicación. La aplicación es eliminada por el sistema operativo sin ninguna posibilidad de limpieza.

Es típico enviar SIGTERMprimero, dormir un rato y luego enviar SIGKILL.

vartec
fuente
Supongo que votar sería un poco más eficiente que dormir (antes del SIGKILL)
Ohad Schneider
@OhadSchneider lo haría, pero eso requeriría algo más que un simple comando bash.
vartec
Sí, supongo que necesitaría hacer un bucle mientras el proceso aún está vivo usando algo como esto: stackoverflow.com/a/15774758/67824 .
Ohad Schneider
5
  • SIGTERM es equivalente a "hacer clic en la 'X'" en una ventana.
  • SIGTERM es lo que Linux usa primero, cuando se cierra.
gbarry
fuente
Eso es lo que quería saber. +1. Gracias.
Luc
6
"SIGTERM es equivalente a" hacer clic en la 'X' "en una ventana" No, no lo es, porque cualquier aplicación puede abrir fácilmente cualquier número de ventanas (documentos y herramientas, por ejemplo), y mucho menos diálogos, y es posible que no incluso responder a un último comando de cierre de ventana como lo hace con un comando de salida (no puedo pensar en ningún ejemplo obvio, pero aunque no es obvio, no hay ninguna razón por la que no se pueda hacer de esa manera). SIGTERM es (o debería ser) equivalente a pedir elegantemente a la aplicación que finalice, sin embargo , eso podría realizarse en esa aplicación en particular .
usuario
3

Con toda la discusión en curso aquí, no se ha ofrecido ningún código. Aquí está mi opinión:

#!/bin/bash

$pid = 1234

echo "Killing process $pid..."
kill $pid

waitAttempts=30 
for i in $(seq 1 $waitAttempts)
do
    echo "Checking if process is alive (attempt #$i / $waitAttempts)..."
    sleep 1

    if ps -p $pid > /dev/null
    then
        echo "Process $pid is still running"
    else
        echo "Process $pid has shut down successfully"
        break
    fi
done

if ps -p $pid > /dev/null
then
    echo "Could not shut down process $pid gracefully - killing it forcibly..."
    kill -SIGKILL $pid
fi
Ohad Schneider
fuente
0

HUP me suena a basura. Lo enviaría para que un demonio volviera a leer su configuración.

SIGTERM puede interceptarse; sus demonios pueden tener código de limpieza para ejecutar cuando reciba esa señal. No puede hacer eso por SIGKILL. Por lo tanto, con SIGKILL no le está dando ninguna opción al autor del demonio.

Más sobre eso en Wikipedia

innaM
fuente