Pregunta

Tengo algunos procesos que muestran como <defunct> en top (y ps). He hervido cosas abajo de las secuencias de comandos y programas reales.

En mi crontab:

* * * * * /tmp/launcher.sh /tmp/tester.sh

El contenido de launcher.sh (que es, por supuesto marcados ejecutable):

#!/bin/bash
# the real script does a little argument processing here
"$@"

El contenido de tester.sh (que es, por supuesto marcados ejecutable):

#!/bin/bash
sleep 27 & # the real script launches a compiled C program in the background

ps muestra lo siguiente:

user       24257 24256  0 18:32 ?        00:00:00 [launcher.sh] <defunct>
user       24259     1  0 18:32 ?        00:00:00 sleep 27

Tenga en cuenta que no aparece tester.sh -. Que haya salido después de lanzar el trabajo en segundo plano

¿Por qué launcher.sh pegarse alrededor, marcado <defunct>? Sólo parece hacer esto cuando lanzado por cron -. No cuando corro yo mismo

Nota adicional: launcher.sh es un guión común en el sistema se ejecuta en esta, que no se modifica fácilmente. Las otras cosas (crontab, tester.sh, incluso el programa que corro en lugar de sleep) se pueden modiified mucho más fácilmente.

¿Fue útil?

Solución

Debido a que no han sido objeto de una llamada al sistema wait(2).

Desde que alguien puede esperar a que estos procesos en el futuro, el núcleo puede no completamente deshacerse de ellos o que no será capaz de ejecutar la llamada al sistema wait porque no tendrá el estado de salida o evidencia de su existencia más.

Al iniciar uno de la cáscara, su cáscara está atrapando SIGCHLD y hacer varias operaciones de espera de todos modos, así que nada permanece desaparecida por mucho tiempo.

Pero cron no se encuentra en un estado de espera, que está durmiendo, por lo que el niño desaparecido puede quedarse por un tiempo hasta que se despierta cron.


Actualización: En respuesta a comentar ... Hmm. Me las arreglé para duplicar el problema:

 PPID   PID  PGID  SESS COMMAND
    1  3562  3562  3562 cron
 3562  1629  3562  3562  \_ cron
 1629  1636  1636  1636      \_ sh <defunct>
    1  1639  1636  1636 sleep

Por lo tanto, lo que ocurrió fue, pienso:

  • horquillas cron y niño cron comienza shell
  • shell (1636) comienza sid y pgid 1636 y comienza sueño
  • shell salidas, SIGCHLD enviados a cron 3562
  • señal se ignora o se maneja mal
  • shell convierte zombi. Tenga en cuenta que el sueño se reasocian a init, así que cuando el sueño sale init obtener la señal y limpiar. Todavía estoy tratando de averiguar cuando el zombi se cosechó. Probablemente sin hijos activos cron 1629 se da cuenta de que puede salir, en ese momento el zombi se reasocian a init y obtener segada. Así que ahora nos preguntamos acerca de la SIGCHLD perdido que cron debería haber procesado.
    • No es necesariamente culpa vixie de cron. Como se puede ver aquí, libdaemon instala un controlador SIGCHLD durante daemon_fork(), y esto podría interferir con la entrega de la señal en una salida rápida por intermedio de 1629

      Ahora, ni siquiera saben si cron vixie en mi sistema Ubuntu sea construido con libdaemon, pero al menos tengo una nueva teoría. :-)

Otros consejos

Sospecho que cron está a la espera para todos los subprocesos en la sesión se interrumpa. Ver esperar (2) con respecto a los argumentos negativos pid. Se puede ver la SESS con:

ps faxo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm

Esto es lo que veo (editado):

STAT  EUID  RUID TT       TPGID  SESS  PGRP  PPID   PID %CPU COMMAND
Ss       0     0 ?           -1  3197  3197     1  3197  0.0 cron
S        0     0 ?           -1  3197  3197  3197 18825  0.0  \_ cron
Zs    1000  1000 ?           -1 18832 18832 18825 18832  0.0      \_ sh <defunct>
S     1000  1000 ?           -1 18832 18832     1 18836  0.0 sleep

Tenga en cuenta que el pescado y el sueño son de la misma Ses.

Utilice el comando setsid (1). Aquí es tester.sh:

#!/bin/bash
setsid sleep 27 # the real script launches a compiled C program in the background

Tenga en cuenta que no es necesario &, setsid pone en el fondo.

a mi opinión es causada por crond proceso (generada por crond para cada tarea) a la espera de la entrada en la entrada estándar que se canaliza al stdout / stderr del comando en el crontab. Esto se hace porque cron es capaz de enviar por correo de salida resultante para el usuario.

Así crond está esperando EOF hasta que el comando de usuario y procesos hijos todo lo que está engendró haber cerrado la tubería. Si esto se hace crond continúa con la espera-declaración y luego el comando de usuario desaparecida desaparece.

Así que creo que hay que desconectar de forma explícita cada subproceso generado en el script formar el tubo (por ejemplo, mediante la redirección a un archivo o / dev / null.

por lo que la siguiente línea debe trabajar en el crontab:

* * * * * ( /tmp/launcher.sh /tmp/tester.sh &>/dev/null & ) 

Me recomendar que a resolver el problema simplemente no tener dos procesos separados: Tener launcher.sh hacer esto en su última línea:

exec "$@"

Esto eliminará el proceso superfluo.

He encontrado esta pregunta mientras yo estaba buscando una solución con un problema similar. Desafortunadamente respuestas en esta pregunta no solucionaron mi problema.

Matar proceso desaparecida no es una opción como sea necesario para encontrar y matar a su proceso padre. Terminé matar a los procesos inactivos de la siguiente manera:

ps -ef | grep '<defunct>' | grep -v grep | awk '{print "kill -9 ",$3}' | sh

En "grep ''" se puede limitar la búsqueda a un proceso desaparecida específica que está después.

He probado el mismo problema tantas veces. Y finalmente tengo la solución. Sólo especifique el '/ bin / bash' antes de la escritura del golpe, como se muestra a continuación.

* * * * * /bin/bash /tmp/launcher.sh /tmp/tester.sh
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top