Question

J'ai des processus montrant comme <defunct> dans top (et ps). Je l'ai fait bouillir les choses des vrais scripts et programmes.

Dans mon crontab:

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

Le contenu de launcher.sh (ce qui est bien sûr le signe exécutable):

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

Le contenu de tester.sh (ce qui est bien sûr le signe exécutable):

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

ps montre les éléments suivants:

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

Notez que tester.sh ne semble pas -. Il a quitté après le lancement de la tâche d'arrière-plan

Pourquoi est-ce launcher.sh rester, marqué <defunct>? Il semble que de le faire lors de son lancement par cron -. Pas quand je cours moi-même

Note complémentaire: launcher.sh est un script commun dans le système fonctionne sur ce qui n'est pas facile à modifier. Les autres (crontab, tester.sh, même le programme que je cours au lieu de sleep) peuvent être modiified beaucoup plus facilement.

Était-ce utile?

La solution

Parce qu'ils ont pas fait l'objet d'un appel système wait(2).

Comme quelqu'un peut attendre que ces processus dans l'avenir, le noyau ne peut pas complètement se débarrasser d'eux ou il ne sera pas en mesure d'exécuter l'appel système wait car il ne sera pas le statut de sortie ou la preuve de son existence plus.

Lorsque vous démarrez un de la coquille, votre coquille est le piégeage SIGCHLD et de faire diverses opérations d'attente de toute façon, rien ne reste disparu depuis longtemps.

Mais Cron est pas dans un état d'attente, il dort, pour que l'enfant défunt peut rester pendant un certain temps jusqu'à ce que se réveille Cron vers le haut.


Mise à jour: En réponse aux commentaires ... Hmm. J'ai réussi à reproduire le problème:

 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

Alors, ce qui est arrivé était, je pense:

  • fourches et Cron enfant commence shell Cron
  • shell (1636) commence sid et pgid 1636 et commence le sommeil
  • sorties shell, SIGCHLD envoyé à 3562 cron
  • signal est ignoré ou mal géré
  • shell devient zombie. Notez que le sommeil est reparented à init, alors quand le sommeil sort init obtenir le signal et nettoyer. Je suis encore à essayer de comprendre quand le zombie se moissonnée. Probablement sans enfants actifs sur les chiffres 1629 cron il peut sortir, à ce moment-là le zombie sera reparented à init et se moissonnée. Alors maintenant, nous nous interrogeons sur l'SIGCHLD manquant qui Cron aurait dû traiter.
    • Il est pas nécessairement la faute de cron Vixie. Comme vous pouvez le voir ici, libdaemon installe un gestionnaire de SIGCHLD pendant daemon_fork(), et cela pourrait interférer avec la livraison du signal sur une sortie rapide par 1629 intermédiaire

      maintenant, je ne sais même pas si cron Vixie sur mon Ubuntu est le système même construit avec libdaemon, mais au moins je une nouvelle théorie. :-)

Autres conseils

Je soupçonne que Cron attend tous les sous-processus de la session pour terminer. Attentiste (2) par rapport aux arguments pid négatifs. Vous pouvez voir le SESS avec:

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

Voici ce que je vois (édité):

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

Notez que le poisson et le sommeil sont dans la même ESSE.

Utilisez la commande setsid (1). Voici tester.sh:

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

Notez que vous n'avez pas besoin &, setsid il met en arrière-plan.

à mon avis, il est causé par le processus crond (engendrés par crond pour chaque tâche) en attente pour l'entrée sur stdin qui est canalisée vers la sortie standard / stderr de la commande dans la crontab. Cela se fait parce que Cron est capable d'envoyer par courrier sortie résultant à l'utilisateur.

crond attend EOF jusqu'à ce que la commande de l'utilisateur et tout ce qu'il a donné naissance à des processus enfants ont fermé le tuyau. Si cela se fait crond se poursuit avec la déclaration d'attente puis la commande utilisateur défunt disparaît.

Alors, je pense que vous devez vous déconnecter explicitement tous les sous-processus donné naissance dans votre script forme la conduite (par exemple en le redirigeant vers un fichier ou / dev / null.

la ligne suivante devrait fonctionner dans crontab:

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

Je vous recommande de résoudre le problème simplement de ne pas avoir deux processus distincts: Avez-launcher.sh faire sur sa dernière ligne:

exec "$@"

Cela permettra d'éliminer le processus superflu.

Je trouve cette question alors que je cherchais une solution à un problème similaire. Malheureusement, les réponses à cette question n'a pas résolu mon problème.

Tuer processus défunt n'est pas une option que vous avez besoin de trouver et de tuer son processus parent. J'ai fini par tuer les processus défunts de la manière suivante:

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

Dans « grep » vous pouvez restreindre la recherche à un processus défunt spécifique que vous recherchez.

Je l'ai testé le même problème tant de fois. Et enfin, j'ai la solution. Il suffit de spécifier le '/ bin / bash' avant que le script bash comme indiqué ci-dessous.

* * * * * /bin/bash /tmp/launcher.sh /tmp/tester.sh
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top