Créer un sous-processus en Unix/Linux, en utilisant la
commande system(), de la bibliothèque standard de C
<stdlib.h>
L'appel système fork() permet de créer des processus fils :
on regarde la valeur de retour de fork(), qui peut être :
. 0 pour le processus fils
. Strictement positive pour le processus père et qui correspond
au pid du processus fils
. Négative si la création de processus a échoué, s'il n'y a pas
suffisamment d'espace mémoire ou si bien le nombre maximal de
créations autorisées est atteint.
//Ce programme créera une chaîne de n-1 processus
//Faire omettre ces instructions?
Le père se termine avant le fils
Le programme tfork.cpp suivant créera deux processus
qui vont modifier la variable a :
#include <sys/types.h> // pour le type pid_t
#include <unistd.h> // pour fork
#include <stdio.h> // pour perror, printf
int a=20;
int main ()
{ pid_t pid;
switch (pid = fork())
{ case -1:
/* ici pid est -1, the fork échoué */
/* raisons possibles: manque d’espace mémoire ou le */
/* ou nombre maximal de créations autorisées est atteint */
perror("The fork failed!");
break;
case 0:// seul le processus fils exécute ce « case »
/* pid zero est le fils */
printf("ici le processus fils %d, le PID de mon père est %d. \n",getpid(),getppid());
a+=10;
break;
default:// seul le processus père exécute cette instruction
/* pid plus grand que zero est le parent prenant le pid du fils */
printf("ici processus père, le PID de mon fils est %d. \n",pid);
a+=100;
}// les deux processus exécutent ce qui suit
printf("Fin du Process %d. avec a = %d\n", getpid(),a );
return 0; }
Quelle est la différence entre les programmes fork1.c et fork2.c suivants ?
Combien de fils sont crées?
Les appels système wait(), waitpid() et exit()
Ces appels système permettent au processus père d'attendre la
fin d'un de ses processus fils et de récupérer son status de fin.
Ainsi, un processus peut synchroniser son exécution avec la n de
son processus fils en exécutant l'appel système wait(). La syntaxe
de l'appel système est :
pid = wait(status);
. wait() : Permet à un processus père d'attendre jusqu'à ce
qu'un processus fils termine. Il retourne l'identifiant du
processus ls et son état de terminaison dans &status.
. waitpid() : Permet à un processus père d'attendre jusqu'à ce
que le processus ls numéro pid termine. Il retourne l'identifiant
du processus fils et son état de terminaison dans &status.
. void exit() : Permet de finir volontairement l'exécution d'un
processus et donne son état de terminaison
Pour éviter le problème des processus pères qui meurent
avant leurs fils dans le programme fork2.c, il suffit d'ajouter une
boucle sur l'appel wait. Dès qu'il ne restera plus aucun fils, l'appel
retournera aussitôt une valeur négative. On saura alors que l'on
peut sortir sans problème
L'exécution asynchrone entre processus parent et fils a certaines
conséquences. Souvent, le fils d'un processus se termine, mais
son père ne l'attend pas. Le processus fils devient alors un
processus zombie
# include < unistd.h> //zombie
# include < stdlib.h> //dans tty ajouter zombie &
# include < sys/types.h> // puis ps -u jmtorres
int main ( )
{
pid_t pid;
pid = fork ( ) ;
if( pid > 0 )
{
sleep( 30 ) ;
}else
{
// F i l s : quitter immédiatement
exit ( 0 ) ;
}
return 0 ;
}
La famille des appels système exec
Un processus fils créé peut remplacer son code de
programme par un autre programme. Le système Unix offre
une famille d'appels système exec
qui permettent de changer l'image d'un processus. Tous les
appels système exec remplacent le processus courant par un
nouveau processus construit à partir d'un fichier ordinaire
exécutable. Les segments de texte et de données du processus
sont remplacés par ceux du fichier exécutable
. execl() : permet de passer un nombre fixé de paramètres au nouveau
programme.
. execv() : permet de passer un nombre libre de paramètres au nouveau
programme.
. execle() : même fonctionnement qu'execl() avec en plus, un argument envp
qui représente un pointeur sur un tableau de pointeurs sur des chaînes de
caractères définissant l'environnement.
. exelp() : Interface et action identiques à celles d'execl(), mais la différence
vient du fait que si le nom du chier n'est pas un nom complet . par rapport à la
racine . le système utilisera le chemin de recherche des commandes . les
chemins indiqués par la variable PATH. pour trouver dans quel répertoire se
trouve le programme.
. exevp() : Interface et action identiques à celles d'execv(), mais la différence
vient du fait que si le nom de chier n'est pas un nom complet, la commande
utilise les répertoires spécifiés dans PATH.
# include < unistd.h>
# include < stdio.h>
# include < sys/types.h>
int main ( int argc , char *argv [ ] )
{ pid_t fils_pid ;
// Liste d'arguments pour la comande " l s "
char *args [ ] = { " ls " , "-l " , argv [ 1 ] , NULL} ;
// Dupliquer le processus
fils_pid = fork ( ) ;
if (fils_pid!=0) { // Il s'agit du père
waitpid ( fils_pid ,NULL,NULL) ;
printf ( "Programme principal termine\n" ) ;
return 0 ; }
else
{
// Executer programme avec les arguments a partir du PATH
execvp ( " ls " , args ) ;
// Retourner en cas d' erreur
perror ( " Erreur dans execvp" ) ;
exit (1) ;
} return 0 ; }
Ces diapositifs sont basés sur :
Andrew S. Tanenbaum Modern operating system Publisher:
Prentice Hall PTR 1992
Gilles Chalimard Administration d'un système Linux ENI
editions 2014
Richard Petersen Linux: The Complete Reference McGraw-
Hill 2008
https://www.technologuepro.com/cours-systemes-
exploitation-2 (2019)
https://perso.liris.cnrs.fr/karim.sehaba/#Enseignements(201
9)
http://www.iro.umontreal.ca/~poulin/ift6800/ (2019)
http://www.univ-
orleans.fr/user/lifo/Members/Mirian.Halfeld/mi-SE-
L2.html(2019)
http://www.groupes.polymtl.ca/inf3600/documentation/(2019
)