Un processus en lance un autre avec fork
Sous Linux, un processus est un programme en cours d’exécution, et chaque processus naît d’un autre grâce à l’appel système fork. Comprendre fork, exec et wait explique ce que fait un interpréteur de commandes quand vous tapez le nom d’un programme.
Un serveur web lance un petit programme pour chaque image à réduire. Si le serveur n’attend jamais la fin de ces programmes, la liste des processus se remplit de fantômes.
À la fin de cette leçon
Remarque
Je peux expliquer comment un processus en lance un autre avec fork, exec et wait.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Processus | un programme en cours d’exécution, avec sa mémoire à lui | |
| fork | l’appel qui crée une copie du processus | fork() |
| exec | l’appel qui remplace le programme du processus par un autre | |
| wait | l’appel qui attend la fin d’un fils | |
| Code de sortie | le nombre que rend un processus qui se termine | exit(3) |
| Zombie | un fils terminé que son père n’a pas encore attendu |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
fork crée une copie du processus
Après fork, il y a deux processus identiques : le père et le fils. Ils reprennent juste après l’appel, chacun avec sa propre mémoire.
La valeur rendue par fork les distingue. Le fils reçoit 0. Le père reçoit le numéro du fils, son pid. Un test if (pid == 0) écrit donc le code du fils.
wait attend le fils et lit son code
Un fils qui se termine rend un code de sortie, un petit nombre. Zéro veut dire « tout s’est bien passé » par convention. Le père lit ce code avec waitpid.
Tant que le père n’a pas attendu, le fils terminé reste dans la table des processus comme un zombie. Attendre un fils le libère.
Un fils sort avec 3, le père attend
pid_t pid = fork();
if (pid == 0) {
printf("enfant\n");
exit(3);
}
waitpid(pid, &etat, 0);Aller dans le dossier de travail
mkdir -p ~/c && cd ~/cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire le programme dans un fichier
printf '#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/wait.h>\nint main(void) {\n pid_t pid = fork();\n if (pid == 0) {\n printf("enfant\\n");\n fflush(stdout);\n exit(3);\n }\n int etat;\n waitpid(pid, &etat, 0);\n printf("parent: fini avec %%d\\n", WEXITSTATUS(etat));\n return 0;\n}\n' > bifurque.cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Compiler et lancer le programme
gcc -Wall -o bifurque bifurque.c && ./bifurqueAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
exec remplace le programme, sans créer de processus
Un fils créé par fork fait le même travail que son père. Pour lancer un autre programme, il appelle exec.
Cet appel remplace tout le code et la mémoire du processus par ceux du nouveau programme. Le pid reste le même, et la ligne qui suit exec ne s’exécute jamais, sauf si l’appel a échoué. Un interpréteur de commandes fait donc fork, puis exec dans le fils, puis wait.
Écrire le programme qui appelle exec
printf '#include <stdio.h>\n#include <unistd.h>\nint main(void) {\n printf("avant\\n");\n fflush(stdout);\n execl("/bin/echo", "echo", "bonjour", (char *)NULL);\n printf("apres\\n");\n return 0;\n}\n' > remplace.cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Compiler et lancer le programme
gcc -Wall -o remplace remplace.c && ./remplaceAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Les fork dessinent un arbre de processus
Chaque fork ajoute un fils sous son père : les processus forment un arbre. Un fils hérite du programme de son père à l’instant du fork, puis exec peut le changer.
Le diagramme montre un interpréteur qui lance ls et sort. Le premier fils se termine, le père l’attend.
Écrire un programme avec deux fork
printf '#include <stdio.h>\n#include <unistd.h>\nint main(void) {\n fork();\n fork();\n puts("x");\n return 0;\n}\n' > deux.cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Compter les lignes écrites
gcc -Wall -o deux deux.c && ./deux | wc -lAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Erreur fréquente
Attention
Beaucoup de gens pensent que fork lance un nouveau programme. Il fait une copie du processus qui l’appelle, et c’est exec qui change de programme. Deux fork à la suite donnent quatre processus, pas deux.