6 Attente de terminaison d'un processus fils
La primitive
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait (int *status) ;
suspend l'exécution du processus appelant jusqu'à ce qu'un de ses
processus fils se termine. Si un processus fils s'est déjà terminé,
wait() retourne le résultat immédiatement.
wait() retourne le pid du processus fils si le retour
est dû à la terminaison d'un processus fils ; -1 en cas d'erreur.
Si status n'est pas un pointeur nul, le status du processus fils
(valeur retournée par exit()) est mémorisé à l'emplacement pointé
par status.
De manière plus précise :
-
l'octet de poids faible est un code indiquant pourquoi le
processus fils s'est arrêté ;
- si le processus fils a effectué un appel à exit(),
l'octet précédent contient le code de retour.
Ces informations peuvent être accédées facilement à l'aide des macros
suivantes définies dans sys/wait.h. (Attention, ces macros
utilisent le status, et non un pointeur sur ce status.) :
-
WIFEXITED (status)
- renvoie vrai si le statut
provient d'un processus fils qui s'est terminé normalement ;
- WEXITSTATUS (status)
- (si WIFEXITED (status)
renvoie vrai) renvoie le code de retour du processus fils passé à
_exit() ou exit() ou la valeur retournée par la fonction
main() ;
- WIFSIGNALED (status)
- renvoie vrai si le statut
provient d'un processus fils qui s'est terminé à cause de la
réception d'un signal ;
- WTERMSIG (status)
- (si WIFSIGNALED (status)
renvoie vrai) renvoie la valeur du signal qui a provoqué la
terminaison du processus fils.
D'autres macros sont disponibles ; leur documentation est accessible
par la commande man 2 wait.
Exemple
% cat status_fils.c
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
main (void)
{
pid_t pid ;
int status ;
pid = fork () ;
switch (pid) {
case -1 :
perror ("fork") ;
exit (1) ;
case 0 : /* le fils */
printf ("processus fils\n") ;
exit (2) ;
default : /* le pere */
printf ("pere: a cree processus %d\n", pid) ;
wait (&status) ;
if (WIFEXITED (status))
printf ("fils termine normalement: status = %d\n",
WEXITSTATUS (status)) ;
else
printf ("fils termine anormalement\n") ;
}
}
% ./status_fils
pere: a cree processus 907
processus fils
fils termine normalement: status = 2
Exercice 3
Donner un programme qui affiche, dans l'ordre, les entiers de 0 à
3 par 4 processus à partir de la structure suivante ;
for (i=0 ; i < 4 ; i++) {
switch (fork ()) {
case -1 :
...
case 0 :
...
default :
...
}
Exercice 4 [Trifourche]
Écrire la fonction
trifourche (void(*)(void), void(*)(void), void(*)(void)) ;
Le processus exécutant trifourche (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.
Cette fonction est par exemple utilisée dans le contexte suivant :
void fa (void)
{
sleep (4) ;
printf ("Fonction fa executee par le processus %d\n", getpid ()) ;
}
void fb (void)
{
sleep (2) ;
printf ("Fonction fb executee par le processus %d\n", getpid ()) ;
}
void fc (void)
{
sleep (3) ;
printf ("Fonction fc executee par le processus %d\n", getpid ()) ;
}
int main (void)
{
trifourche (fa, fb, fc) ;
printf ("Terminaison de main ()\n") ;
}
Exercice 5 [Multifourche]
La fonction multifourche() généralise la fonction
trifourche() précédente.
typedef int (*intint ) (int) ;
void multifourche (int n, intint f[]) ;
Le type intint est défini comme « pointeur sur une fonction
retournant d'entier à entier ». Les arguments de
multifourche() sont un tableau de telles fonctions et la
taille n de ce tableau. Chacune des fonctions est exécutée
par un processus différent qui affiche aussi le valeur retournée
par la fonction.
Exercice 6
Soit la commande sigma à deux arguments. sigma inf
sup affiche la somme des entiers de inf à sup.
En remarquant que l'on peut calculer indépendamment
åi=a,b-a/2 i et åb-a/2+1, b i
pour calculer sigma a b, développer une version de la
commande sigma utilisant des processus.
Exercice 7
Soit le programme suivant compilé en un exécutable nommé
partage :
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main (void)
{
char buf [6] ;
int fd ;
fd = open ("foo", O_RDWR, 420) ;
switch (fork ()) {
case -1 :
perror ("fork") ;
exit (1) ;
case 0 :
printf ("%d caracteres ecrits\n", write (fd, "12345", 5)) ;
break ;
default :
printf ("%d caracteres lus\n", read (fd, buf, 5)) ;
buf [5] = '\0' ;
printf ("Ligne lue : %s\n", buf) ;
close (fd) ;
}
}
Donner le résultat de la séquence de commandes Unix suivante :
% echo ABCDEFGH > foo
% ./partage
% cat foo