Finalité

Les deux programmes ont pour but de démontrer la possibilité d'exécuter des commandes en tâche de fond. Dans ces exemples, il sera lancé quelques commandes sleep en tâche de fond, la finalité étant de ne sortir du programme qu'à la fin de l'exécution de tous les processus enfants, ceci pour contrôler leur correcte exécution. Le deuxième script permet de terminer un process qui dépasse un certain temps (timeout).

Exemple 3 - le patient

Le script fourni en exemple 3 est disponible ici:

Remarquez le code suivant:

set -o monitor
trap "childexit" CHLD

Cela permet d'exécuter la fonction childexit() dès qu'un processus fils se termine. En effet, la commande trap permet d'intercepter des signaux externes dont la fin d'un processus fils. (man bash)
Tous les processus sont lancés de la même manière, une variable $pid contient tous les PID.
L'attente commence alors grâce à la fonction waitall() qui se charge de:

  • attendre qu'un processus fils se termine,
  • afficher le code retour de processus (grâce au wait).
Cinématique

Les actions sont les suivantes:

  • le script initialise la trap sur le signal CHILD.
  • le script lance des commandes en arrière plan puis attend que tous les processus se terminent.
  • la fonction waitall() vérifie si un des processus fils à déjà terminé (kill -0) puis attend indéfiniment (waitsignal()).
  • un processus fils quitte, la trap childexit() s'exécute
  • on termine prématurément la fonction waitsignal() en kill'ant le sleep depuis la trap childexit().
  • la fonction waitall() reprend son cours et revérifie si un processus fils a quitté et affiche son code retour. Son PID est enlevé de la variable $pid.
  • si la variable $pid est vide (plus de processus fils), on rend la main à l'appelant.
Pour
  • simple
  • très efficace
  • gestion correcte des codes retour
Contre
  • pas de timeout (attente infinie)
  • ne marche qu'en bash (set -o monitor)

Exemple 4 - le patient, mais pas trop

Le script fourni en exemple 4 est disponible ici:

Le script reprend le même principe que l'exemple 3, cependant, la durée d'attente de terminaison des processus fils est paramétrable par la variable MAXTIMEOUT.

L'attente infinie est remplacée par une attente limitée (7 secondes dans l'exemple). Si au bout de ces 7 secondes, des processus fils sont toujours en vie, un signal SIGTERM leur est envoyé.

Remarquez le code suivant, juste après avoir lancé la fonction timedwait():

timedwait
if [ $? -eq 0 ]; then
[..]
fi

Cela vérifie la code retour de timedwait(). En effet, si le sleep de la fonction timedwait() est kill'é par la trap CHILD (=fin d'un processus fils), son code retour sera différent de 0 et la fonction waitall() refera une vérification des processus fils. Par contre, si la fonction timedwait() atteint son terme (=timeout), le code retour sera alors 0 et un signal kill sera envoyé à tous les processus fils via la fonction killallchilds().

Pour
  • Simple
  • Efficace
  • Peu de chance d'attente infinie
Contre
  • Ne marche qu'avec Bash

Conclusion

Bash n'est pas seulement capable de lancer quelques commandes de manière séquentielle, il est tout à fait possible de gérer les processus multitâches. Bien sûr, on est très loin des performances offertes par d'autres langage mais permet de faire quelques traitements en simultané.