Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

Processus : fork, exec et wait

Après cette leçon: Je peux expliquer comment un processus en lance un autre avec fork, exec et wait.

Leçon de 60 min7 commandesLab de compilation et d’architecture : gcc, flex, bison et RISC-V dans une VM

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

MotCe que ça veut direExemple
Processusun programme en cours d’exécution, avec sa mémoire à lui
forkl’appel qui crée une copie du processusfork()
execl’appel qui remplace le programme du processus par un autre
waitl’appel qui attend la fin d’un fils
Code de sortiele nombre que rend un processus qui se termineexit(3)
Zombieun 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

Code: c
pid_t pid = fork();
if (pid == 0) {
    printf("enfant\n");
    exit(3);
}
waitpid(pid, &etat, 0);

Aller dans le dossier de travail

Commande
mkdir -p ~/c && cd ~/c

Affiché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

Commande
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.c

Affiché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

Commande
gcc -Wall -o bifurque bifurque.c && ./bifurque

Affiché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

Commande
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.c

Affiché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

Commande
gcc -Wall -o remplace remplace.c && ./remplace

Affiché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

Commande
printf '#include <stdio.h>\n#include <unistd.h>\nint main(void) {\n    fork();\n    fork();\n    puts("x");\n    return 0;\n}\n' > deux.c

Affiché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

Commande
gcc -Wall -o deux deux.c && ./deux | wc -l

Affiché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.

À propos de ce labo et de sa source: Lab de compilation et d’architecture : gcc, flex, bison et RISC-V dans une VM

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.