Domanda

Ho alcuni processi che mostrano come <defunct> in top (e ps). Ho bollito le cose dagli script e programmi reali.

Nel mio crontab:

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

Il contenuto di launcher.sh (che è ovviamente segnati eseguibile):

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

Il contenuto di tester.sh (che è ovviamente segnati eseguibile):

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

ps mostra quanto segue:

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

Si noti che tester.sh non appare -. Che è uscito dopo il lancio del processo in background

Perché launcher.sh restare, segnato <defunct>? Sembra solo per fare questo quando lanciato da cron -. Non quando l'eseguo io

Nota aggiuntiva: launcher.sh è uno script comune nel sistema gira su questo, che non è facilmente modificabile. Le altre cose (crontab, tester.sh, anche il programma che ho eseguito, invece di sleep) possono essere modiified molto più facilmente.

È stato utile?

Soluzione

Perché non sono stati oggetto di una chiamata di sistema wait(2).

Dal momento che qualcuno potrebbe aspettare che questi processi in futuro, il kernel può non completamente sbarazzarsi di loro o non sarà in grado di eseguire la chiamata di sistema wait perché non avrà lo stato di uscita o la prova della sua l'esistenza di più.

Quando si avvia uno dalla shell, la shell è intrappolando SIGCHLD e facendo varie operazioni di attesa comunque, quindi niente rimane defunta per lungo tempo.

Ma cron non è in uno stato di attesa, si sta dormendo, in modo che il bambino defunta può restare per un po 'fino a quando si sveglia cron.


Aggiornamento: In risposta a commentare ... Hmm. Sono riuscito a duplicare il 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

Quindi, quello che è successo è stato, penso:

  • forchette cron e bambino cron avvia shell
  • shell (1636) inizia a sid e pgid 1636 e comincia il sonno
  • shell uscite, SIGCHLD inviati a cron 3562
  • segnale viene ignorato o utilizzata in maniera impropria
  • shell gira zombie. Si noti che il sonno è reparented a init, in modo che quando il sonno esce init ottenere il segnale e la pulizia. Sto ancora cercando di capire quando lo zombie viene raccolto. Probabilmente senza figli attivi cron 1629 figure out si può uscire, a quel punto lo zombie sarà reparented di init e ottenere raccolto. Così ora ci chiediamo circa il SIGCHLD mancante che avrebbe dovuto cron elaborati.
    • Non è necessariamente colpa vixie di cron. Come si può vedere qui, libdaemon installa un gestore di SIGCHLD durante daemon_fork(), e questo potrebbe interferire con la consegna del segnale su una rapida uscita da intermedio 1629

      Ora, io non so nemmeno se vixie cron sul mio sistema Ubuntu è anche costruito con libdaemon, ma almeno ho una nuova teoria. :-)

Altri suggerimenti

Ho il sospetto che cron è in attesa di tutti i sottoprocessi nella sessione per terminare. Vedere attendere (2) per quanto riguarda gli argomenti pid negativi. Si può vedere il SESS con:

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

Ecco quello che vedo (a cura):

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

Si noti che il pesce e il sonno sono nella stessa Sess.

Utilizzare il comando setsid (1). Ecco tester.sh:

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

Si noti che non è necessario &, setsid mette in background.

per il mio parere è causata da crond processo (generato da crond per ogni compito) in attesa di input su standard input che viene convogliata al output / error del comando nel crontab. Ciò avviene perché cron è in grado di inviare l'output risultante via posta per l'utente.

Quindi crond è in attesa di EOF fino al comando utente e processi figli tutto è generato hanno chiuso il tubo. Se questo è fatto crond prosegue con l'attesa-dichiarazione e poi il comando utente defunta scompare.

Quindi penso che si deve disconnettere in modo esplicito ogni sottoprocesso deposto le uova nello script formare il tubo (per esempio riorientando in un file o / dev / null.

in modo che la riga seguente dovrebbe funzionare in crontab:

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

Vorrei raccomandare che si risolve il problema semplicemente non avere due processi separati: Avere launcher.sh fare questo sulla sua ultima riga:

exec "$@"

Ciò elimina il processo di superfluo.

Ho trovato questa domanda mentre ero alla ricerca di una soluzione con un problema simile. Purtroppo le risposte a questa domanda non ha risolto il mio problema.

Uccidere processo defunto non è un'opzione come è necessario trovare e uccidere il suo processo genitore. Ho finito per uccidere i processi defunti nel seguente modo:

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

In "grep ''" è possibile restringere la ricerca ad uno specifico processo defunta siete dopo.

Ho testato lo stesso problema così tante volte. E finalmente ho la soluzione. Basta specificare il '/ bin / bash' prima che lo script bash come illustrato di seguito.

* * * * * /bin/bash /tmp/launcher.sh /tmp/tester.sh
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top