segundo - procesos en background y foreground linux
¿Linux mata los procesos en segundo plano si cerramos el terminal desde el que se inició? (4)
¿Quién debería matar empleos?
Normalmente, los trabajos en primer plano y en segundo plano son eliminados por SIGHUP
enviados por el kernel o el shell en diferentes circunstancias.
¿Cuándo el kernel envía SIGHUP
?
Kernel envía SIGHUP
al proceso de control :
- para terminal real (hardware): cuando se detecta una desconexión en un controlador de terminal, p. ej., en la línea de módem;
- para pseudoterminal (pty): cuando el último descriptor que hace referencia al lado maestro de pty está cerrado, por ejemplo, cuando cierra la ventana de terminal.
Kernel envía SIGHUP
a otros grupos de proceso:
- al grupo de proceso de primer plano , cuando el proceso de control termina;
- al grupo de proceso huérfano , cuando queda huérfano y ha dejado de miembros.
El proceso de control es el líder de la sesión que estableció la conexión con el terminal de control.
Típicamente, el proceso de control es tu shell. Así que para resumir:
- el kernel envía
SIGHUP
al shell cuando se desconecta / cierra real o pseudoterminal; - el kernel envía
SIGHUP
al grupo de proceso en primer plano cuando el shell termina; - el kernel envía
SIGHUP
al grupo de procesos huérfanos si contiene procesos detenidos.
Tenga en cuenta que el kernel no envía SIGHUP
al grupo de procesos en segundo plano si no contiene procesos detenidos.
¿Cuándo bash
envía SIGHUP
?
Bash envía SIGHUP
a todos los trabajos (primer plano y fondo):
- cuando recibe
SIGHUP
y es un shell interactivo (y el soporte de control de trabajos está habilitado en tiempo de compilación); - cuando sale, es un shell de inicio de sesión interactivo y se
huponexit
opciónhuponexit
(y se habilita el soporte de control de trabajos en tiempo de compilación).
Ver más detalles here .
Notas:
-
bash
no envíaSIGHUP
a trabajos eliminados de la lista de trabajos usandodisown
; - los procesos comenzaron a usar
nohup
ignorarSIGHUP
.
Más detalles here .
¿Qué pasa con otras conchas?
Por lo general, las conchas se propagan SIGHUP
. Generar SIGHUP
en la salida normal es menos común.
Telnet o SSH
Bajo telnet o SSH, debe ocurrir lo siguiente cuando se cierra la conexión (por ejemplo, cuando cierra la ventana de telnet
en la PC):
- el cliente es asesinado
- el servidor detecta que la conexión del cliente está cerrada;
- el servidor cierra el lado maestro de pty;
- el kernel detecta que la pty maestra está cerrada y envía
SIGHUP
abash
; -
bash
recibeSIGHUP
, envíaSIGHUP
a todos los trabajos y termina; - Cada trabajo recibe
SIGHUP
y termina.
Problema
Puedo reproducir su problema usando bash
y telnetd
desde el servidor SSH de busybox
o dropbear
: a veces , el trabajo en segundo plano no recibe SIGHUP
(y no finaliza) cuando se cierra la conexión del cliente.
Parece que se produce una condición de carrera cuando el servidor ( telnetd
o telnetd
) cierra el lado maestro de pty:
- normalmente,
bash
recibeSIGHUP
e inmediatamente mata los trabajos en segundo plano (como se espera) y termina; - pero a veces,
bash
detectaEOF
en el lado esclavo de pty antes de manejarSIGHUP
.
Cuando bash
detecta EOF
, de forma predeterminada termina inmediatamente sin enviar SIGHUP
. ¡Y el trabajo de fondo sigue en marcha!
Solución
Es posible configurar bash
para enviar SIGHUP
en la salida normal (incluido EOF
) también:
Asegúrese de que
bash
se inicia como shell de inicio de sesión . Elhuponexit
here solo para shells de inicio de sesión, AFAIK.El shell de inicio de sesión se habilita mediante la opción
-l
o el guiónargv[0]
enargv[0]
. Puede configurartelnetd
para ejecutar/bin/bash -l
o mejor/bin/login
que invoca/bin/sh
en el modo shell de inicio de sesión.P.ej:
telnetd -l /bin/login
Habilitar la opción
huponexit
.P.ej:
shopt -s huponexit
Escriba esto en la sesión de
bash
cada vez o agréguelo a.bashrc
o/etc/profile
.
¿Por qué ocurre la carrera?
bash
desbloquea las señales solo cuando es seguro y las bloquea cuando alguna sección de código no puede ser interrumpida de manera segura por un manejador de señales.
Dichas secciones críticas invocan puntos de interrupción de vez en cuando, y si se recibe una señal cuando se ejecuta una sección crítica, su controlador se retrasa hasta que se produce el siguiente punto de interrupción o se abandona la sección crítica.
Puede comenzar a excavar desde quit.h
en el código fuente.
Por lo tanto, parece que en nuestro caso, a veces, bash
recibe SIGHUP
cuando está en una sección crítica. SIGHUP
ejecución del controlador SIGHUP
se retrasa, y bash
lee EOF
y termina antes de salir de la sección crítica o llamar al siguiente punto de interrupción.
Referencia
- Sección "Control de trabajos" en el manual oficial de Glibc.
- Capítulo 34 "Grupos de procesos, sesiones y control de trabajos" del libro "La Interfaz de programación de Linux".
Tengo un sistema integrado, en el que hago telnet
y luego ejecuto una aplicación en segundo plano:
./app_name &
Ahora si cierro mi terminal y hago telnet
desde otra terminal y si lo compruebo, puedo ver que este proceso todavía se está ejecutando.
Para comprobarlo he escrito un pequeño programa:
#include<stdio.h>
main()
{
while(1);
}
Ejecuté este programa en mi computadora local de Linux en segundo plano y cerré la terminal.
Ahora, cuando verifiqué este proceso desde otra terminal, descubrí que este proceso también fue cancelado.
Mi pregunta es:
- ¿Por qué comportamiento indefinido para el mismo tipo de proceso?
- ¿De cuál es dependiente?
- ¿Depende de la versión de Linux?
AFAIK en ambos casos el proceso debe ser matado. Para evitar esto, debes emitir un nohup como el siguiente:
> nohup ./my_app &
De esta manera su proceso continuará ejecutándose. Probablemente la parte de telnet se deba a un error similar a este:
Cuando cierras el terminal, el shell envía SIGHUP
a todos los procesos en segundo plano, y eso los mata. Esto se puede suprimir de varias maneras, sobre todo:
nohup
Cuando ejecutas un programa con nohup
, captura SIGHUP
y redirige la salida del programa.
$ nohup app &
desconocer
disown
le dice a shell que no envíe SIGHUP
$ app &
$ disown
¿Depende de la versión de linux?
Depende de tu concha. Lo anterior se aplica al menos para bash .
Para comprender completamente lo que está sucediendo, debe ingresar un poco a los unix
internos de unix
.
Cuando está ejecutando un comando como este
./app_name &
El nombre de app_name
se envía al grupo de proceso en segundo plano. Puedes consultar los grupos de proceso de unix
here
Cuando cierra bash
con salida normal, se dispara la señal de SIGHUP
a todos sus trabajos. Alguna información sobre el control de trabajo de unix
está here .
Para mantener su aplicación en ejecución cuando salga de bash
, debe hacer que su aplicación sea inmune a la señal de nohup
con la utilidad nohup
.
nohup - ejecuta un comando inmune a los cuelgues, con salida a un no-tty
Y finalmente así es como necesitas hacerlo.
nohup app_name & 2> /dev/null;