Professional Documents
Culture Documents
Processus
3.1 Processus
3.1.1 tats dun processus
Lorsquun processus sexcute, il change dtat, comme on peut le voir
sur la figure ??. Il peut se trouver alors dans lun des trois tats principaux :
lu : en cours dexcution.
Prt : en attente du processeur.
Bloqu : en attente dun vnement.
Initialement, un processus est ltat prt. Il passe ltat excution
lorsque le processeur entame son excution. Un processus passe de ltat
excution ltat prt ou lorsquil est suspendu provisoirement pour per-
mettre lexcution dun autre processus. Il passe de ltat excution ltat
bloqu sil ne peut plus poursuivre son excution (demande dune E/S). Il
se met alors en attente dun vnement (fin de lE/S). Lorsque lvnement
1
2 CHAPITRE 3. PROCESSUS
Interruption
Prt Excution
lu
Bloqu
Nouveau Fin
Interruption
Admis Termin
Prt Excution
lu
Bloqu
(PCB).
relancer le processus courant dans le mme tat. Par exemple, il faut ab-
solument se rappeler quelle instruction il est rendu. La figure ?? illustre
le changement de contexte entre processus. Le processsus en cours est in-
terrompu et un ordonnanceur est ventuellement appel. Lordonnanceur
sexcute en mode kernel pour pouvoir manipuler les PCB. Le changement
de contexte sera expliqu plus en dtail dans le Chapitre ??, Ordonnance-
ment de processus.
excution
Charger tat de PCB B
i n t main ( )
{
int return_value ;
/ r e t o u r n e 1 2 7 s i l e s h e l l ne peut pas s e x e c u t e r
retourne 1 en c a s d e r r e u r
autrement r e t o u r n e l e code de l a commande /
r e t u r n _ v a l u e = system ( " l s l /" ) ;
10 return return_value ;
}
Il cre un processus fils en lanant la commande :
ls -l /
dans un shell. Il faut retenir que system() nest pas un appel systme,
mais une fonction C. Ce qui rend lutilisation de la fonction system()
moins performante quun appel systme de cration de processus. Ceci sera
discut la fin de la section.
#include <unistd.h>
int fork();
3.3. CRATION DE PROCESSUS 7
fork() est le seul moyen de crer des processus, par duplication dun
processus existant1 . Lappel systme fork() cre une copie exacte du pro-
cessus original, comme illustr la figure ??. Mais maintenant il se pose un
problme, car les deux processus pre et fils excutent le mme code. Com-
ment distinguer alors le processus pre du processus fils ? Pour rsoudre ce
pile pile
i 27 i 0
i= fork() i= fork()
co co
F IG . 3.5 Processus pre et son fils clon. i=27 aprs lappel fork() pour
le pre et i=0 pour le fils. Limage mmoire est la mme pour tous les deux,
notamment le compteur ordinal co.
1
Linux a introduit un autre appel systme pour la cration de contexte dun processus :
clone(). Cest un appel systme trs puissant, avec un nombre darguments pour grer la
mmoire par le programmeur. Malheureusement clone() ne fait pas partie de la norme
Posix, et ne sera pas tudi ici. Le lecteur intress peut consulter, par exemple, les articles
du Linux Journal, http ://www.linuxjournal.com
8 CHAPITRE 3. PROCESSUS
pid = 13
pre
fils i = fork()
i=0 i=27
pid = 27 pid = 13
i n t main ( )
{
pid_t f i l s _ p i d ;
f i l s _ p i d=fork ( ) ;
i f ( f i l s _ p i d ==0)
10 p r i n t f ( " J e s u i s l e f i l s avec pid %d\n " , g e t p i d ( ) ) ;
else i f ( f i l s _ p i d > 0 )
p r i n t f ( " J e s u i s l e pere avec pid %d\n " , g e t p i d ( ) ) ;
else
p r i n t f ( " E r r e u r dans l a c r e a t i o n du f i l s \n " ) ;
}
Lexcution de fils.c montre les pid du pre et du fils :
i n t main ( void )
{
int i , j , k,
n=5;
pid_t f i l s _ p i d ;
10 f o r ( i = 1 ; i <n ; i ++)
{
f i l s _ p i d = fork ( ) ;
i f ( f i l s _ p i d > 0 ) // c e s t l e pere
break ;
}
Ce programme crera une chane de
processus :
Le problme ici est que dans tous les cas le processus pre se termine
avant le processus fils. Comme tout processus doit avoir un parent, le pro-
cessus orphelin est donc "adopt" par le processus 1 (le processus init).
Ainsi, on peut remarquer quau moment o les processus affichent le nu-
mro de leur pre, ils ont dj te adopts par le processus init.
i n t main ( void )
{
pid_t p ;
int a = 20;
10
// c r a t i o n d un f i l s
switch ( p = f o r k ( ) )
{
case 1:
// l e f o r k a echoue
p e r r o r ( " l e f o r k a echoue ! " ) ;
break ;
case 0 :
// I l s a g i t du p r o c e s s u s f i l s
20 p r i n t f ( " i c i p r o c e s s u s f i l s , l e PID %d . \ n " , g e t p i d ( ) ) ;
a += 10;
break ;
default :
// I l s a g i t du p r o c e s s u s pere
p r i n t f ( " i c i p r o c e s s u s pere , l e PID %d . \ n " , g e t p i d ( ) ) ;
a += 100;
}
// l e s deux p r o c e s s u s e x e c u t e n t c e t t e i n s t r u c t i o n
p r i n t f ( " Fin du p r o c e s s u s %d avec a = %d . \ n " , g e t p i d ( ) , a ) ;
3.3. CRATION DE PROCESSUS 11
30 return 0 ;
}
Deux excutions du programme tfork.cpp montrent que les processus
pre et fils sont concurrents :
i n t main ( )
{
int i , n=5;
int childpid ;
10 f o r ( i = 1 ; i <n ; i ++)
{
i f ( ( c h i l d p i d = f o r k ( ) ) < = 0 ) break ;
p r i n t f ( " P r o c e s s u s %d avec pere %d , i=%d\n " , g e t p i d ( ) ,
getppid ( ) , i ) ;
}
return 0 ;
}
12 CHAPITRE 3. PROCESSUS
i n t main ( )
{
int i , n=5;
p i d _ t pid ;
10 f o r ( i = 1 ; i <n ; i ++)
{
i f ( ( pid= f o r k ( ) ) = = 1 )
break ;
i f ( pid = = 0 )
p r i n t f ( " P r o c e s s u s %d avec pere %d , i=%d\n " , g e t p i d ( ) ,
getppid ( ) , i ) ;
}
return 0 ;
20 }
La sortie de fork1.c est assez comprehensible. chaque retour de lappel
de fork(), on sort de la boucle si on est dans un processus fils (valeur de
retour gale 0), ou si lappel a chou (valeur de retour ngative). Si le
shell, qui le pre du processus cre lors de lexcution de fork1, a un pid
de 759, et le processsus lui-mme un pid = 904 , on aura la sortie suivante :
pas le cas, puisquencore une fois des processus pres meurent avant que
leur fils ne puissent afficher leurs messages :
shell = 759
fork1 = 874
889
F IG . 3.7 Arbre que nous obtiendrions avec fork2.c si les processus pres
ne mourraient pas avant que les fils aient pu afficher leurs messages.
14 CHAPITRE 3. PROCESSUS
#include <sys/wait.h>
int wait (int *status);
int waitpid(int pid, int *status, int options);
void exit(int return_code);
i n t main ( )
{
pid_t f i l s _ p i d ;
f i l s _ p i d =fork ( ) ;
i f ( f i l s _ p i d ==0)
10 p r i n t f ( " J e s u i s l e f i l s avec pid %d\n " , g e t p i d ( ) ) ;
else i f ( f i l s _ p i d > 0 ) {
p r i n t f ( " J e s u i s l e pere avec pid %d . \ n " , g e t p i d ( ) ) ;
p r i n t f ( " J a t t e n d s que mon f i l s se termine\n " ) ;
wait (NULL) ;
}
else
p r i n t f ( " E r r e u r dans l a c r e a t i o n du f i l s \n " ) ;
20 exit (0);
}
16 CHAPITRE 3. PROCESSUS
i n t main ( )
{
int i , n=5;
i n t pid ;
10 f o r ( i = 1 ; i <n ; i ++)
{
i f ( ( pid= f o r k ( ) ) = = 1 )
break ;
i f ( pid = = 0 )
p r i n t f ( " P r o c e s s u s %d avec pere %d , i=%d\n " , g e t p i d ( ) ,
getppid ( ) , i ) ;
}
// Attendre l a f i n des f i l s
20 while ( wait (NULL) > = 0 ) ;
return 0 ;
}
void f i l s ( i n t i ) ;
i n t main ( )
{
3.3. CRATION DE PROCESSUS 17
int status ;
i f ( f o r k ( ) ) // c r e a t i o n du premier f i l s
10 {
i f ( f o r k ( ) = = 0 ) // c r e a t i o n du second f i l s
fils (2) ;
}
else f i l s ( 1 ) ;
i f ( wait (& s t a t u s ) > 0 )
p r i n t f ( " f i n du f i l s %d\n " , s t a t u s > > 8 ) ;
i f ( wait (& s t a t u s ) > 0 )
p r i n t f ( " f i n du f i l s %d\n " , s t a t u s > > 8 ) ;
return 0 ;
20 }
void f i l s ( i n t i )
{
sleep ( 2 ) ;
exit ( i ) ;
}
Deux excutions du programme deuxfils-1.c :
void f i l s ( i n t i ) ;
i n t main ( )
{
int status ;
10 p i d _ t pid ;
18 CHAPITRE 3. PROCESSUS
// C r e a t i o n du premier f i l s
pid = f o r k ( ) ;
i f ( pid = = 1 ) p e r r o r ( " f o r k " ) ;
e l s e i f ( pid = = 0 ) f i l s ( 1 ) ;
// C r e a t i o n du second f i l s
pid = f o r k ( ) ;
i f ( pid = = 1 ) p e r r o r ( " f o r k " ) ;
20 e l s e i f ( pid = = 0 ) f i l s ( 2 ) ;
// A t t e n t e de t e r m i n a i s o n des deux f i l s
// I c i on a t t e n d l a f i n d un t r o i s i e m e f i l s qui n e x i s t e pas
// Une e r r e u r s e r a r e t o u r n e e
i f ( wait (& s t a t u s ) > 0 )
p r i n t f ( " f i n du f i l s %d\n " , WEXITSTATUS ( s t a t u s ) ) ;
e l s e p e r r o r ( " wait " ) ;
return 0 ;
}
40
// Routine pour l e s f i l s
void f i l s ( i n t i )
{
sleep ( 2 ) ;
exit ( i );
}
Excution du programme deuxfils-2.c :
fork()
exit() zombie
i n t main ( )
{
p i d _ t pid ;
20 CHAPITRE 3. PROCESSUS
fork() exit()
F IG . 3.9 Processus orphelin : le pre meurt avant le fils. init adopte len-
fant.
// p r o c e s s u s f i l s
10 pid = f o r k ( ) ;
i f ( pid > 0 )
{
// Pere : dormir 3 0 secondes
sleep ( 3 0 ) ;
}
else
{
// F i l s : q u i t t e r immediatement
exit ( 0 ) ;
20 }
return 0 ;
}
Excution de zombie.c en tche de fond : la commande ps permet de
constater son tat zombie avant et aprs son disparition dfinitive :
leibnitz> gcc -o zombie zombie.c
leibnitz> zombie &
[1] 5324
leibnitz> ps -u jmtorres
PID TTY TIME CMD
2867 pts/0 00:00:00 tcsh
5324 pts/0 00:00:00 zombie
5325 pts/0 00:00:00 zombie <defunct>
5395 pts/0 00:00:00 ps
leibnitz>
3.3. CRATION DE PROCESSUS 21
execv execvp
execve
#include <unistd.h>
int execl(const char *path, const char *argv, ...);
int execv(const char *path, const char *argv[]);
int execle(const char *path, const char *argv,
const char *envp[]);
int execlp(const char *file, const char *argv, ...);
int execvp(const char *file, const char *argv[]);
22 CHAPITRE 3. PROCESSUS
char *arguments[4]
...
arguments[0]="/bin/ls";
arguments[1]="-l";
arguments[2]="/etc";
arguments[3]="NULL";
execv("/bin/ls", arguments);
...
pid_t f i l s _ p i d ;
// Dupliquer l e p r o c e s s u s
f i l s _ p i d = fork ( ) ;
if ( fils_pid ! = 0 ) {
// I l s a g i t du pere
waitpid ( f i l s _ p i d ,NULL,NULL) ;
p r i n t f ( " Programme p r i n c i p a l termine \n " ) ;
return 0 ;
}
20 else
{
// E x e c u t e r programme avec l e s arguments a p a r t i r du PATH
execvp ( " l s " , a r g s ) ;
// Retourner en c a s d e r r e u r
p e r r o r ( " E r r e u r dans execvp " ) ;
exit (1);
}
return 0 ;
30 }
Excution de fork-exec.cpp :
i n t main ( void )
{
int p , child , status ;
p= f o r k ( ) ;
10 i f ( p == 1)
return 1;
i f ( p > 0 ) // i l s a g i t du pere c a r p > 0
{
p r i n t f ( " I c i l e pere [%d ] , mon f i l s [ %d]\n " , g e t p i d ( ) , p ) ;
i f ( ( c h i l d =wait (& s t a t u s ) ) > 0 )
p r i n t f ( " I c i pere [%d ] , f i n du f i l s [%d]\n " , g e t p i d ( ) , c h i l d ) ;
// Dormir pendant une seconde
sleep ( 1 ) ;
p r i n t f ( " Le pere [%d ] se termine \n " , g e t p i d ( ) ) ;
20 }
else
{ // i l s a g i t du f i l s
i f ( ( status=execl (
"/home/ada/ u s e r s / j m t o r r e s / i n f 3 6 0 0 / l o g i c i e l /a . out " ,
3.3. CRATION DE PROCESSUS 25
i n t main ( )
{
p r i n t f ( " i c i programme f i l s [%d ] \ n " , g e t p i d ( ) ) ;
return 0 ;
}
Excution des programmes parent.cpp et fils.cpp. Remarque : Le fi-
chier excutable de fils.cpp est a.out :
10 }
e l s e i f ( wait (NULL) > 0 )
p r i n t f ( " Le pere d e t e c t e l a f i n du f i l s \n " ) ;
return 0 ;
}
Excution du programme texecvp.cpp :
3.4 Exercices
1. Dans le systme Unix, est-ce que tout processus a un pre ?
2. Que se passe-t-il lorsquun processus devient orphelin (mort de son
pre) ?
3. Quand est-ce quun processus passe ltat zombie ?
4. Pour lancer en parallle plusieurs traitements dune mme applica-
tion, vous avez le choix entre les appels systme pthread_create()
et fork(). Laquelle des deux possibilits choisir ? Pourquoi ?
5. Quaffiche chacun des segments de programme suivants :
(a) for (i=1; i<=4; i++)
{
pid = fork();
if (pid != 0) printf("%d\n", pid);
}