#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main (void) { int i; pid_t pid; for (i=0; i<3; i++) { pid=fork(); if (pid == -1) { /* erreur */ perror("erreur fork"); exit(EXIT_FAILURE); } else if (pid == 0) { /* fils */ fprintf(stderr, "fils : %d\n", i); } else { /* pere */ fprintf(stderr, "pere : %d\n", i); } } exit(EXIT_SUCCESS); }
Figure 1: Que fait ce programme ?
Clonage interactif
Le nombre de processus pouvant être lancés par un utilisateur, mais aussi par le système sont limités.
Si un programme (erroné) crée des processus en boucle, on risque de ne plus pouvoir allouer de processus, même pour tuer ledit programme.
On peut se garder de telles erreurs en TP en utilisant la fonction suivante
pid_t ifork() { fprintf(stderr, "fork() %d ? (^C to abort) ", getpid()); fflush(stderr); getchar(); return fork(); }La saisie d’un retour chariot suffit à accepter le fork().
Exercice 2 (Quatre fils)Question 1 Donnez un programme qui affiche les entiers de 0 à 3 par 4 processus différents. L’exécution de ce programme se termine après l’affichage des 4 entiers.Question 2 Assurez que les processus fils affichent les entiers dans l’ordre croissant.
Exercice 3 (Tri fourche) Écrivez une fonctionLe processus exécutant trif(f1, f2, f3) engendre des processus exécutant respectivement les fonctions f1(), f2(), et f3(), et attend la fin des processus engendrés pour terminer la fonction.void trif (void(*f1)(void), void(*f2)(void), void(*f3)(void));Cette fonction est par exemple utilisée dans le contexte suivant :
static void f(int seconds, const char *fname) { sleep(seconds) ; fprintf(stderr, "Fonction %s() executee par le processus %d\n", fname, getpid()) ; } static void fa(void) { f(4, "fa"); } static void fb(void) { f(2, "fb"); } static void fc(void) { f(3, "fc"); } int main(void) { trif(fa, fb, fc); fprintf(stderr, "terminaison de main()\n"); exit(EXIT_SUCCESS); }
Exercice 4 (Multi fourche) La fonction multif() généralise la fonction trif() précédente.Le type func_t est défini comme « pointeur sur une fonction à un paramètre entier retournant un entier ».typedef int (*func_t) (int); int multif (func_t f[], int args[], int n);Les arguments de multif() sont un tableau de telles fonctions, un tableau des arguments à passer à ces fonctions, et la taille n de ces tableaux. Chacune des fonctions est exécutée par un processus différent. (La fonction f[i](arg[i] sera appelée avec arg[i] comme valeur de paramètre.) Ce processus se termine en retournant comme statut la valeur de la fonction.
La fonction multif() se termine elle-même en retournant la conjonction des valeurs retournées par les processus fils : elle ne retourne une valeur vraie que si chacun des processus fils a retourné une valeur vraie.
Exercice 5 (Pas de zombis) Un processus ne désirant pas interagir avec son fils ne peut l’abandonner. À sa terminaison, le fils passerait en l’état zombi.Cependant, considérant qu’un processus orphelin est adopté par le processus init de PID 1, on peut utiliser la technique dite du double fork :
- le père engendre un processus fils dont le rôle est d’engendrer à son tour un processus petit-fils qui réalisera le travail ; ce processus fils termine aussitôt ;
- à sa terminaison le petit-fils, orphelin sera adopté par init ;
- le père attend la terminaison de son fils qui doit survenir rapidement.
Question 1 Donnez le code d’une fonctionqui utilise la technique du double fork pour faire exécuter le fonction f() par un processus petit fils.typedef void (*func_t) (void *); void forkfork(func_t f, void *arg);Question 2 Comment faire en sorte que le père récupère le PID de son petit-fils ?Question 3 Que pensez, en terme de coût de copie mémoire, de cette technique du double fork ?
![]()
![]()