Skip to content

MOOC NSI - fondamentaux.

Transcription de la vidéo

4.2.2.6 : Communication inter-processus II

[00:00:01]

Nous allons parler maintenant d'un premier cas de communication entre processus et nous allons voir comment les processus père peuvent communiquer avec leur fils. Ici, nous reprenons le même exemple que dans la séquence vidéo précédente où nous avons un père et un fils qui travaillent avec leurs propres variables i. Nous avons rendu l'exemple un peu plus bavard et avons mis des affiches pour les deux processus ,pour leur demander quel est leur identifiant et quel est l'identifiant de leur père. Si nous regardons la trace d'exécution, nous voyons que le père a un identifiant 5969, mais quand le fils affiche l'identifiant du père, au lieu de voir ce numéro, nous voyons qu'il affiche comme père un processus avec numéro 1. Pourquoi? En effet, un processus peut se terminer pour différentes raisons. Il peut se terminer parce qu'il a fini de faire ce qu'il avait à faire, il peut y avoir une erreur ou alors il a pu être tué par un autre processus qui a les droits. Dans tous les cas, il faut que le processus père se préoccupe du sort de son fils puisque dans le cas d'une terminaison prématurée, peut être qu'il faut faire des actions, peut être que le père doit réagir. C'est pour cela que le père est obligé d'attendre la terminaison du processus fils et de consulter les informations sur le statut de terminaison pour voir s' il doit effectuer certains traitements ou pas.

[00:01:50]

Si le père ne le fait pas, nous avons un processus fils abandonné qui ne fait plus rien puisqu'il est terminé, mais qui par contre occupe des ressources système. On appelle ces processus des processus zombies et puisqu'ils occupent des ressources pour rien et donc entravent le bon fonctionnement du système, le système d'exploitation, dont beaucoup de cas se charge de les adopter et donc de traiter leur terminaison. C'est pour cela qu'ici, effectivement, le 1 que nous voyons, c'est l'identifiant du processus, le premier qui a été lancé, qui est le processus init, et c'est lui qui récupère le fil et qui s'occupe de cette terminaison puisque dans le programme que nous avons, le père ne fait rien de particulier pour s'occuper de la terminaison de son fils. Comment devrait faire le père? Donc, voici le programme avec la partie où le père attend son fils. Nous l'avons rendu un petit peu plus long , il y a un petit peu plus compliqué. Alors, dans la partie du fils qui a la partie if, il y a un premier affichage, mais ensuite, pour prolonger l'exécution du fils, nous avons mis une boucle qui va s'exécuter dix fois et où, à chaque itération, le fils va dormir pendant trois secondes et ensuite va imprimer, fils avec le numéro d'itération. A la fin, après la boucle, le fils va se terminer en appelant la fonction exit et en donnant explicitement un code de retour qui est un code farfelu ici qu'est le 22.

[00:03:36]

Du côté du père, il y a aussi un premier affichage et ensuite le père aussi, pour qu'il soit un peu plus long, on a mis une boucle qui s'exécutera 10 fois. Par contre, le père ne va dormir que pendant une seconde et il va afficher lui aussi le numéro d'itération. Ce que nous faisons après pour le père, c'est que nous le forçons à attendre la terminaison du fils. Pour faire cela, il doit faire appel à la fonction waitpid. Donc, wait - attendre pid - le processus dont l'identifiant et donné en argument. Et donc, nous donnons en argument newpid qui contient la valeur retournée par qui est l'identifiant du fils. Si, au moment de l'appel de cette fonction, le fils n'est pas terminé, le processus père va être bloqué. Il va attendre. Une fois que le processus fils se termine, le père va être débloqué, va pouvoir donc récupérer les informations de terminaison du fils qui sont données comme (en) retour de la fonction waitpid et va pouvoir vérifier si, oui ou non, le fils s'est terminé normalement. Il y a donc une macro WIFEXITED : si elle retourne vrai, ça veut dire que le fils s'est terminé normalement, sinon, ça veut dire qu'il s'est terminé soit à cause d'une erreur, soit parce qu'on l'a forcé à se terminer. En regardant l'affichage que nous obtenons lors d'une exécution de ce programme, donc ça commence bien par le père qui dit qu'il est 37455 et qu'il vient de créer un fils …

[00:05:23]

… 37458. Ensuite, c'est le fils qui prend la main. Et il affiche que son identifiant est bien le 37458. Ensuite, il redonne la main au père qui fait 2 itérations et donc affiche 0 1. Le fils intervient et il affiche 0. C'est sa première itération. Vu que le père dort moins longtemps, il a le temps de faire 3, 4. Ensuite, le fils fait 1, le père 5, 6, 7, le fils 2. Le père termine avec 8, 9. (Donc on voit bien que les deux processus sont entrelacés) et. Le fils continue avec sa boucle. Ce qui est important, c'est de voir que le waitpid joue bien son rôle, donc le père ne se termine pas après le 9, mais (il) est obligé d'attendre que le fils termine sa boucle. Et quand ce fils se termine, il récupère l'information qu’il s'est terminée normalement et il récupère bien le code de retour 22. Ceci est possible grâce au système d'exploitation. Donc, je vous rappelle que le système d'exploitation est l'entité qui gère tous les processus et donc qui peut détecter la terminaison d'un processus. C'est le système qui gère la terminaison d'un processus qui peut récupérer le code de retour et qui peut donc aller réveiller le processus père en lui passant ce code de retour.

[00:07:09]

Ce mécanisme de communication entre père et fils est quelque chose qui est utilisé tout le temps dans un programme que vous connaissez maintenant bien, qui est l'interpréteur de commandes, le shell. En effet, je vous rappelle le shell, c'est celui qui attend à ce que l'utilisateur tape quelque chose, qui interprète ce qui est tapé et qui donc l’exécute si c'est une commande valable. En effet, le shell est structuré de la manière suivante : il exécute toujours la même chose, donc il boucle, il récupère ce que l'utilisateur a tapé, donc la ligne de commande, il vérifie que c'est une commande valide et si c'est une commande valide, il va créer un processus fils qui va exécuter cette commande. C'est quelque chose que nous avons vu dans les séquences précédentes, nous avons vu qu'effectivement, quand nous lancions des programmes, si nous affichions le numéro du père, on avait vu que c'était le numéro du shell. Donc, le shell crée un processus fils qui va exécuter la commande. Et donc, si nous avons lancé, cela s'appelle en premier plan, cela veut dire que le shell va attendre la terminaison du fils. Donc exactement ce que nous venons de voir dans les transparents précédents. Et pendant qu'il attend la terminaison du fils, c'est-à-dire la fin d'exécution de la commande, l'utilisateur ne va pas pouvoir interagir avec le shell.

[00:08:38]

Et donc, si on essaye de taper ici sur le terminal, il n'y a rien qui va se passer. Ici, l'exemple que je vous montre, c'est une boucle qui se déroule et donc, pendant qu'elle se déroule, elle affiche les numéros d'itération. L'utilisateur n'a pas la main, donc il ne peut pas interagir avec le shell. Ici c'est pour vous montrer effectivement vous rappeler que si je lance un petit programme shell-fils et c'est le programme qui est donné dans le code à gauche qui ne fait qu'afficher le numéro du père et le numéro du programme (le processus qui exécute le programme), nous voyons bien que le père de ce processus il a le numéro 99359, qui est bien le numéro de shell, comme montré par la commande ps plus haut.

Dans cette séquence, nous avons vu un premier mécanisme basique de communication entre processus qui est utilisé dans le cas des pères et des fils. Donc, le système d'exploitation permet au père d'attendre un fils et de récupérer les informations de terminaison. Ce mécanisme est à la base du fonctionnement des interpréteurs de commandes. Si les pères sont irresponsables et n'attendent pas la terminaison des fils et ne gèrent donc pas cette terminaison, le système d'exploitation risque de voir apparaître des processus qui ne font plus rien d'utile, mais qui occupent des ressources système qui sont appelés des processus zombies.