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 affiche le code de retour Résultat attendu : .. code-block:: console $ gcc -std=c2x -Wall -Wextra -pedantic -g p4e1.c -o p4e1 && ./p4e1 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 : .. code-block:: console $ gcc -std=c2x -Wall -Wextra -pedantic -g p4e2.c -o p4e2 && ./p4e2 [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 : .. code-block:: console $ gcc -std=c2x -Wall -Wextra -pedantic -g p4e3.c -o p4e3 && ./p4e3 ... contenu de p4e3.c ... Parent: enfant terminé (OK) p4e4 - Intercepter SIGINT (Ctrl+C) ---------------------------------- 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 avec ``pause()`` jusqu’à réception de ``SIGINT`` - Affiche ensuite ``strsignal(last_signal)`` Résultat attendu : .. code-block:: console $ gcc -std=c2x -Wall -Wextra -pedantic -g p4e4.c -o p4e4 && ./p4e4 PID=12345. Appuyez sur Ctrl+C pour envoyer SIGINT. ^C Signal reçu : 2 (Interrupt) 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 : .. code-block:: console $ gcc -std=c2x -Wall -Wextra -pedantic -g p4e5.c -o p4e5 && ./p4e5 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 : .. code-block:: console $ gcc -std=c2x -Wall -Wextra -pedantic -g p4e6.c -o p4e6 && ./p4e6 [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:raw-latex:`\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 : .. code-block:: console $ gcc p4e7_reader.c -o reader && gcc 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 : .. code-block:: console $ gcc -std=c2x -Wall -Wextra -pedantic -g p4e8.c -o p4e8 && ./p4e8 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).