Skip to content

MOOC NSI - fondamentaux.

Transcription de la vidéo

4.2.2.2 : Création de processus

[00:00:01]

Maintenant que nous connaissons les processus, nous allons nous intéresser à la création de processus, c'est -à -dire comment on peut demander au système de créer des processus pour nos besoins. Nous avons vu qu'il y a au moins deux types de processus: les processus système que le système lance pour ses propres besoins et les processus utilisateurs, qui sont lancés pour que les utilisateurs puissent travailler sur la machine. Alors les opérations de lancement et donc de création et de gestion de processus, (ce) sont des opérations sensibles puisqu'elles impactent globalement les performances et la manière de fonctionner de notre système. Donc, ce sont des opérations privilégiées qui sont exécutées par le système d'exploitation. Quand les utilisateurs ont besoin de lancer des choses sur la machine et donc de créer des processus, ils doivent demander au système d'exploitation, via l'interface graphique ou l'interface en ligne de commande ou l'interface programmatique. Pour lancer un programme via l'interface graphique, vous le savez bien, il suffit de cliquer sur l'icône de l'application correspondante. Ici, si je clique sur l'icône de Microsoft Excel, le système d'exploitation va lancer l'application, et si je regarde les processus qui s'exécutent sur le machine, je verrai bien un processus qui s'appelle Excel. Pour lancer en ligne de commande, il suffit de taper le nom du fichier exécutable. Alors en fonction des environnements, on peut taper Firefox directement ou alors, comme ici, j'ai donné le chemin complet vers le fichier exécutable. Alors, les détails sur l'organisation des fichiers en répertoires en arborescence et les notions de chemin pourraient être discutées dans les séquences vidéo qui sont dédiées au système de fichiers.

[00:02:02]

Sous Linux, c'est la même chose. Ici, nous avons le terminal de base sous Ubuntu. Si je tape Firefox pour le lancer, je me retrouve avec l'application et sa fenêtre qui sont montrés ici en partie basse de la capture d'écran.

Regardons maintenant quelque chose qui nous intéresse quand nous travaillons avec le langage Python. Pour lancer un programme Python, je peux bien sûr, donner le nom de l'interpréteur Python suivi par le nom du programme. Si je tape que le nom de l'interpréteur, je me retrouve dans l'environnement qui attend à ce que je tape des instructions Python pour qu'il puisse les évaluer. Nous avons déjà dit dans les séquences précédentes que quand on exécute un programme Python, ce qui est exécuté, le processus qui est derrière, c’est le processus qui correspond à l'interpréteur Python. Effectivement, si je lance Python et quand je regarde la liste des processus, je vois bien mon processus Python qui est si en deuxième ligne.

Pour lancer un programme, je peux faire aussi autrement. Comme vous voyez ici dans l'exemple de terminal, je peux taper directement le nom du programme Python. Comment cela marche? A droite, j'ai le petit programme, donc j'ai mon processus qui exécute la fonction main. La fonction main ne fait qu'un simple affichage. Et quand je tape le nom du programme, qui c’est qui prend en charge ce que j'ai tapé? C'est l'interpréteur de commande, le shell. Dont il regarde si ce fichier est exécutable,

[00:03:44]

et on va parler de ça dans le transparent suivant, il voit qu'il est exécutable et commence à exécuter son contenu. En commençant, il tombe sur la première ligne qui commence par un dièse, un point d'exclamation qui est en effet une directive pour le shell. Et cette directive lui dit que ce qui va suivre, en fait, devrait être interprété par l'environnement python. Donc le shell va lancer l'interpréteur Python qui, lui, va se charger de la suite des opérations.

Alors, pour qu'un fichier soit exécutable, il faut qu’on ait les droits d'exécution. Cela fait partie, de manière plus générale, de la gestion des droits sous Unix, où nous faisons la différence entre différents types d'utilisateurs. Nous avons le propriétaire d'un fichier; ce propriétaire fait partie d'un groupe, typiquement, vous avez le groupe d'élèves, le groupe d'étudiants, le groupe d'enseignants… ; et vous avez tous les autres utilisateurs. Pour chaque type d'opération, et les opérations sont lecture, écriture, exécution, nous allons avoir un bit qui va indiquer si oui ou non nous avons le droit d'exécuter l'opération correspondante. Ainsi, si je regarde le petit tableau à cases à droite, nous avons donc dix cases. La première case sous Unix va nous indiquer le type de fichier. Ensuite, les trois cases qui suivent vont être les droits définis pour le propriétaire. Ensuite, les droits pour le groupe auquel appartient le propriétaire et, à la fin, les droits pour tous les autres utilisateurs. Dans la capture de terminal en dessous ou je regarde les détails sur mon fichier hello.py avec le commande ls -l,

[00:05:39]

Je vois que c'est un fichier normal, c'est le petit tiret qui commence. Ensuite, le propriétaire et le propriétaire, c'est moi vania a tous les droits, j'ai le droit de lecture, le droit d'écriture et le droit d'exécution. Et tous les autres utilisateurs, que ce soit dans le groupe ou en dehors de groupe, ont le droit de lecture et d'exécution. Donc, si on regarde, tout le monde a le droit d'exécuter ce fichier. Si je m'amuse à changer ces droits, par exemple avec la commande, chmod dans la partie basse du transparent, chmod a-x veut dire je change les droits sur le fichier hello.py et à tout le monde, j'enlève le droit d'exécution. Si maintenant je tape la même chose que tout à l'heure, c'est à dire le nom de mon programme hello.py, le shell va voir que je n'ai pas le droit d'exécuter ce fichier et va me le dire. Donc je ne vais pas pouvoir l'exécuter.

Sous Windows, nous avons la même chose : vous avez les propriétés des fichiers où vous pouvez cliquer et définir, donc les droits de lecture, exécution, modification, etc.

La dernière partie de cette vidéo est sur la création de processus en utilisant l'interface programmatique et en particulier la fonction fork. Nous allons regarder cette chose là de manière un peu simplifiée, c'est à dire que nous n'allons pas considérer le cas où fork se termine par un échec, c'est à dire qu'on n'a pas réussi à créer un nouveau processus.

[00:07:19]

Donc, si fork n'échoue pas, quand il est réussi, il va se traduire par la création d'un nouveau processus. Donc, il y a un premier processus qui va appeler la fonction fork et quand cela réussit, nous allons nous retrouver avec deux processus : le premier processus qui s'appelle le processus père et le deuxième processus, qui est une copie conforme du père qui s'appelle le processus fils. Ici, ils sont schématiquement représentés par deux boîtes : à gauche, la boîte du père, à droite, la boîte du fils. Nous allons voir plus tard ce que contiennent ces boîtes exactement. Nous avons donc dans ces boîtes les instructions qui sont exécutées par le programme, en particulier le fork. Donc, le père et le fils sont bien deux processus différents, indépendants, qui s'exécutent en parallèle et qui ont deux identifiants, deux PID, différents Le fils,quand il est créé, quand on dit que c'est une copie conforme du père, ça veut dire que dans la boîte du fils il y a la même chose que dans la boîte du père. Cela veut dire qu’on va avoir les mêmes instructions et le fils se retrouve dans la même situation que le père. C'est à dire que si le père a exécuté toutes les instructions qui ont précédé le fork, alors le fils aussi est dans un état où il a exécuté toutes les instructions qui précèdent le fork. Les deux processus se retrouvent après l'exécution du fork et vont devoir exécuter les instructions qui suivent le fork. Alors, si dans les instructions qui précèdent le fork côté père, nous avons une variable locale i qui a pris la valeur 10.

[00:09:12]

Du côté du fils, nous allons nous retrouver avec une variable locale i qui a pris la valeur 10. Ce qu'il faut comprendre, c'est que ce sont deux i différents. Il y a le i du père et le i du fils. Le père ne peut pas aller voir le i du fils et le fils ne peut pas aller voir le i du père. Tous les deux sont après le folk et vont devoir continuer avec les instructions qui suivent. Et si j'ai mis un simple print. Côté père, donc le print devrait écrire “Je suis” avec le résultat de la fonction getpid qui retourne le numéro, l'identifiant, du processus courant. Donc, côté père, par exemple, j'ai obtenu “Je suis 49335”. Côté fils, vu que c'est une copie, je vais me retrouver avec la même instruction après le fork. Donc le fils aussi va exécuter cette instruction. Par contre, vu que c'est un processus différent avec un identifiant différent, il va imprimer quelque chose de différent comme ici : “Je suis 49336”.

Voici le programme Python correspondant. Il y a deux variantes : à gauche, c'est tout à plat, à droite, j'ai encapsulé le fonctionnement dans la fonction main, ainsi, quand je lance donc le petit programme à droite, je sais qu'il va y avoir un processus qui va être créé, qui va exécuter la fonction main …

[00:10:46]

et dans le main, je vais appeler fork, et si cela marche, je vais me retrouver avec deux processus qui vont devoir exécuter chacun l'instruction print. Quand j'exécute en m'assurant que mon fichier est bien exécutable, je me retrouve bien avec 2 affichages avec deux numéros de processus différents, le premier qui est le père et le deuxième, qui est le fils.

Si je rends les deux processus un peu plus bavards et en plus de leurs propres identifiants, ils impriment aussi l'identifiant de leur père, je me retrouve avec les affichages suivants. Donc ici, si je regarde la deuxième ligne, le processus dit “je suis 56113 et mon père est 56112”. Si on regarde la première ligne, ce processus dit “je suis 56112”, donc le processus qui imprimait la première ligne et est le père du deuxième processus. Donc la première ligne, c'est le père. La deuxième ligne, c'est le fils. Le père, par contre, dit que lui aussi, il a un père avec un numéro 55879. Quel est donc ce processus? Si on utilise la commande ps que nous avons déjà vue et qui donne la liste de processus, si nous l'exécutons dans notre terminal ou y a pas grand chose qui tourne, nous allons voir ici qu' en fait ce numéro 55879 correspond au processus de l'interpréteur de commande qui ici est bash. Ce qui nous fait comprendre que quand nous tapons une commande en ligne de commande, le shell, quand il lit et interprète ce qui doit être exécuté , …

[00:12:43]

en fait, il crée un processus qui se charge de l'exécution de la commande tapée.

Retournons au fork, donc, si il marche, si cet appel marche, nous avons deux processus qui coexistent et ce qui est étonnant, c'est que le fork est appelé une fois par le processus père, mais fork retourne deux valeurs différentes, une pour le père et une pour le fils. Pour le père, fork retourne le numéro du fils qui vient d'être créé, alors qu'au fils le fork retourne 0. 0 n'est pas un nombre valide pour un identifiant de processus. Et donc, tout processus qui récupère 0 en retour de fork comprend qu'il vient d'être créé et qu'il est un processus fils. Ce qui est intéressant par rapport à cette valeur différente qui est envoyée aux deux processus, c'est que nous pouvons l'utiliser pour distinguer les instructions qui devraient être exécutées par le père et celles qui devraient être exécutées par le fils. C'est ce que je vous montre dans le petit exemple à gauche. Nous avons toujours donc le processus qui est créé pour l'exécution de ce programme qui va exécuter la fonction main. Dans main il va faire un premier affichage “[père] mon pid est” avec son numéro et ensuite il va appeler la fonction fork. Comme je l'ai dit, fork, s'il marche, s'il réussit, retourne deux valeurs. Donc, si nous avons deux processus, chez le père, nous allons nous retrouver avec un newpid avec le retour de fork et chez le fils, on va se retrouver avec un autre newpid avec le retour de fork 0. Donc si newpid est 0,

[00:14:46]

cela veut dire que c'est le processus fils qui s'exécute et il va exécuter la première partie du bloc if. Si newpid n’est pas 0, c'est-à -dire il est positif, il correspond au pid du processus fils. Cela veut dire que nous sommes dans le processus père et dans ce cas là, ce qui va être exécuté, c'est la partie qui correspond au else. Les deux processus exécutent la terminaison par exit et si nous regardons l'exécution de ce programme, nous voyons bien les 4 lignes des 4 affichages correspondant. Le père qui exécute donc les deux premières lignes, qui affiche les deux premières lignes et le fils qui affiche les deux dernières lignes. Alors, nous voyons que c'est symétrique, il y a le père qui dit que c'est 7210 et que son fils, c'est 7211 et le fils qui dit qu’il est 7211 et son père est 7210.

Pour résumer cette vidéo, nous avons parlé de création de processus. Nous avons vu que c'est une opération privilégiée qui est exécutée par le système d'exploitation et pour lui demander la création d'un processus un utilisateur peut utiliser l'interface graphique et donc cliquer sur l'icône d'une application, utiliser la ligne de commande en donnant le nom du fichier exécutable, ou alors programmer la création de processus à l'aide de la fonction fork.