Reprenons le schéma vu précédemment :
Figure 3.13 Création d'un processus
Nous allons envisager successivement les deux cas :
- Création d'un processus sans bloquer le père (fig. 3.13a)
- Création d'un processus avec attente du père (fig. 3.13b)
Dans un deuxième temps nous ajouterons à ce dernier schéma le chargement d'un nouveau code pour le fils.
Déroulement en parallèle du père et du fils
/*
Le père n'attend pas le fils qui devient orphelin
*/
#include <stdio.h>
#include <unistd.h>
main()
{
if (fork() == 0) {
fprintf(stdout,"Processus fils %d \n", getpid());
sleep(60); /* le fils dort 60 secondes */
fprintf(stdout,"Le fils est orphelin et disparait");
exit (1);
fprintf(stdout,"Processus père %d \n", getpid());
sleep(15);
fprintf(stdout,"Signal du fils non attendu \n");
exit(0);
}
Notez :
- Le code de retour de la fonction fork() est 0 pour le fils.
- La fonction getpid() permet de récupérer le PID d'un processus.
- Si vous lancez la commande "ps -ef" (dans une autre fenêtre) vous pourrez constater la relation père - fils en examinant le contenu des colonnes PID et PPID (Parent PID).
Mise en attente du père
/*
Le père attend le fils
*/
#include <unistd.h>
#include <stdio.h>
main()
{
int pid, status;
if (fork() == 0) { /* Processus fils */
fprintf(stdout,"processus fils %d\n",getpid());
exit(1);
}
pid = wait(&status);
/* Le père attend le fils. Wait retourne le pid du fils */
fprintf(stdout,"processus père %d\n", getpid());
fprintf(stdout,"sortie du wait\n");
/* Le père attend 15s, le temps que le fils disparaisse */
sleep(15);
fprintf(stdout,"PID = %d, status = %d\n", pid, status);
exit(0);
}
Notez :
- L'usage de la fonction wait pour mettre le père en attente. Si l'on avait lancé plusieurs fils il faudrait placer autant de wait que de processus fils pour bloquer le père. Nous en verrons un exemple au chapitre IV avec l'emploi de pipes.
Chargement d'un nouveau code
Dans l'exemple suivant la création d'un fils s'accompagne d'un appel à la fonction execlp (avater de exec) pour charger un nouveau code pour le fils, donc démarrer un nouveau programme. La fonction execlp prend pour paramètre une chaine de caractères qui correspond à un programme exécutable. Attention execlp n'explore différents chemins et doit donc trouver ce programme dans le répertoire où le père a été lancé. Vous pouvez préparer vos propres codes. A titre d'exemple vous en trouverez deux, très simples, sous ces liens : ex1.c et ex2.c
/*
Création d'un processus et chargement de son code
On fournit au clavier le nom complètement qualifié du code
à charger
*/
#include <unistd.h>
#include <stdio.h>
#include <string.h>
main()
{
int pid, status;
char pgm[20];
fprintf(stdout,"Nom du pg a lancer par le fils : ");
fscanf(stdin,"%s",pgm);
if (fork() == 0) { /* Processus fils */
fprintf(stdout,"processus fils %d execute %s\n",getpid(),pgm);
execlp(pgm,NULL);
fprintf(stderr,"Ce message n'apparait pas si tout va bien ");
fprintf(stderr,"car le code est changé\n");
exit(1);
}
pid = wait(&status);
/* Le père attend le fils. Wait retourne le pid du fils */
fprintf(stdout,"processus père %d\n", getpid());
fprintf(stdout,"PID = %d, status = %d\n", pid, status);
exit(0);
}
Vous pouvez compliler vous même ces codes pour mieux comprendre leur fonctionnement.
Copyright Yves Epelboin, université P.M. Curie, 1998 MAJ
4 avril, 2005