Partie 4 - Processus

p4e1 - Premier fork

Écrivez un programme C qui :

  1. Affiche « Avant le fork, pid = PID »

  2. Crée un processus enfant avec fork()

  3. Le parent affiche : « Je suis le parent, PID = X, mon enfant a le PID = Y »

  4. L’enfant affiche : « Je suis l’enfant, PID = X, mon parent a le PID = Y » puis se termine avec _exit(0)

  5. Le parent attend l’enfant avec wait et récupère le status de fin de l’enfant

  6. Le parent affiche ensuite le code de retour de l’enfant (testez avec l’enfant qui fait un _exit(0) ou _exit(1))

Résultat attendu :

$ gcc -std=c2x -Wall -Wextra -pedantic -g p4/p4e1.c && ./a.out
Avant le fork
Je suis le parent, PID = 12345, mon enfant a le PID = 12346
Je suis l'enfant, PID = 12346, mon parent a le PID = 12345
Parent: enfant terminé normalement, code retour = 0

p4e2 - Copy-on-Write et isolation mémoire

Créez un programme qui montre l’isolation mémoire entre processus :

  • Créez un entier x = 4

  • fork() un processus enfant

  • L’enfant modifie x = 2 et dort 2 secondes

  • Les deux affichent la valeur et l’adresse de x (avec %p)

Résultat attendu :

$ gcc -std=c2x -Wall -Wextra -pedantic -g p4/p4e2.c && ./a.out
[parent] PID=12345              x=4  &x=0x7ffd055fdc60
[child]  PID=12346, PPID=12345  x=2  &x=0x7ffd055fdc60

Les adresses sont identiques mais les valeurs diffèrent. Pourquoi ?

p4e3 - Fork + Exec simple

Écrire un programme qui :

  • fork() un enfant

  • L’enfant exécute la commande cat -n p4e3.c (voir exec). Si exec échoue → perror("exec") puis ``_exit(1)``

  • Le parent attend avec waitpid() et affiche si l’enfant s’est bien terminé

Résultat attendu :

$ gcc -std=c2x -Wall -Wextra -pedantic -g p4/p4e3.c && ./a.out
... contenu de p4e3.c ...
Parent: enfant terminé (OK)

p4e4 - Intercepter SIGTERM et ignorer SIGINT

Programmer un handler via sigaction avec SA_RESTART qui :

  • Enregistre le numéro du dernier signal dans volatile sig_atomic_t last_signal

  • Utilise un drapeau volatile sig_atomic_t stop = 0 pour arrêter la boucle

  • Boucle toutes les secondes pour afficher le PID du processus jusqu’à réception de SIGTERM

  • En cas de réception d’un SIGINT le programme ne doit pas s’arrêter (les ^C affichés ci-dessous représentent un appui sur Ctrl+C qui ne fait rien)

  • Affiche ensuite le numéro du signal et le nom du signal correspondant (avec strsignal(last_signal))

Vous pouvez partir de l”exemple du cours pour avoir une base.

Résultat attendu :

$ gcc -std=c2x -Wall -Wextra -pedantic -g p4/p4e4.c && ./a.out
PID=420928
PID=420928
^CPID=420928
PID=420928
^CPID=420928
PID=420928
PID=420928
PID=420928
Signal reçu : 15 (Terminated)

Testez le programme en envoyant un signal avec la commande kill depuis un autre terminal.

p4e5 - Pipe unidirectionnel parent→enfant

Écrire un programme qui :

  • Crée un pipe(fd)

  • fork() un enfant

  • Le parent écrit un message dans fd[1], puis ferme fd[1]

  • L’enfant lit depuis fd[0] et affiche, puis ferme fd[0]

  • Bien fermer les extrémités inutiles dans chaque processus

Résultat attendu :

$ gcc -std=c2x -Wall -Wextra -pedantic -g p4/p4e5.c && ./a.out
Enfant a reçu : Bonjour depuis le parent !

p4e6 - Ping-pong bidirectionnel avec deux pipes

Écrire un programme parent-enfant utilisant deux pipes :

  • Pipe P1 (parent → enfant)

  • Pipe P2 (enfant → parent)

  • Le parent envoie ping#1, l’enfant lit et répond pong#1

  • Répéter pour N échanges (ex: 5)

  • Afficher chaque message envoyé/reçu

Résultat attendu :

$ gcc -std=c2x -Wall -Wextra -pedantic -g p4/p4e6.c && ./a.out
[Parent] Envoi: ping#1
[Enfant] Reçu: ping#1
[Enfant] Envoi: pong#1
[Parent] Reçu: pong#1
[Parent] Envoi: ping#2
...

p4e7 - FIFO (tube nommé) - Writer & Reader

Créer deux programmes séparés qui communiquent via FIFO :

Programme p4e7_writer.c :

  • Crée mkfifo("canal", 0666) si besoin (gérer EEXIST)

  • Ouvre "canal" en écriture (O_WRONLY) - bloquant jusqu’à un lecteur

  • Envoie "Hello FIFO\n" puis ferme

  • Supprime la FIFO avec unlink("canal")

Programme p4e7_reader.c :

  • Ouvre “canal” en lecture (O_RDONLY) - bloquant jusqu’à un écrivain

  • Lit tout jusqu’à EOF et affiche

  • Ferme le descripteur

Test :

$ gcc p4/p4e7_reader.c -o reader && gcc p4/p4e7_writer.c -o writer
$ ./reader &
[1] 12345
$ ./writer
Hello FIFO
[1]+  Done

p4e8 - Mini-shell avec commandes simples et background

Écrire un mini-shell qui :

  • Affiche un prompt mini-shell>

  • Lit une ligne de commande (avec fgets)

  • Parse les arguments (séparateur espace simple)

  • Lance les commandes dans un fork fork + execvp puis waitpid sur l’enfant

  • Commande interne exit pour quitter le shell

Vous pouvez vous aider de ce tutoriel : https://brennan.io/2015/01/16/write-a-shell-in-c/

Résultat attendu :

$ gcc -std=c2x -Wall -Wextra -pedantic -g p4/p4e8.c && ./a.out
mini-shell> echo hello
hello
mini-shell> sleep 5 &
[bg] PID=12350 lancé en arrière-plan
mini-shell> date
mer. 15 oct. 2025 14:30:12 CEST
mini-shell> exit
Au revoir !

Vous pouvez ajouter petit à petit des éléments à votre shell comme pouvoir lancer des commandes en background quand la ligne se termine par &, créer les fonctions comme cd ou history (voir la commande help dans un terminal bash si vous voulez de l’inspiration).