chapitre 3: Gestion des processus
jnouedoni@[Link]
21 avril 2015
à la fin de ce chapitre, je dois être capable de :
1. Utiliser les primitives C pour créer un processus
2. Exécuter un programme à partir d’un processus
3. Obtenir des informations sur un processus
4. écrire des programmes C manipulant des processus
1 Introduction
Le troisième chapitre de ce cours s’est interessé à la manipulation des pro-
cessus à travers les utilitaires ou les commandes du Système d’exploitation
Unix. Le langage C 1 permet aux programmeurs de créer, exécuter, faire com-
muniquer ou transmettre des signaux à des processus en utilisant directement
les primitives ou instructions C. Ce chapitre s’interesse aux constructions of-
fertes pour la manipulation des processus. Il passe tour en tour en révue : le
mécanisme de création de processus, l’exécution de commandes système ou 2
par les processus, la terminaison des processus et initie à la communication
inter-processus.
2 la création des processus en C
Deux techniques peuvent être utilisées pour créer des processus en C.
La première qui consiste à employer la primitive system() est relativement
simple à utiliser mais se revèle inéfficace et comporte de nombreux risques
sécuritaires. La seconde qui concerne l’usage de la fonction fork() semble
complexe mais offre plus de fiabilité, flexibilité, rapidité et sécurité.
1. Langage à partir duquel le système Unix a été crée
2. autres programmes
Complexe Universitaire Siantou
Cycle Licence profressionnelle
Gestion des ProcessusProgrammation des processus jnouedoni@[Link]
2.1 La primitive system 2
2.1 La primitive system
La fonction system() fournit un procédé simple d’exécution d’une com-
mande du shell à partir d’un programme C de la même façon que si la com-
mande était entrée à partir d’un shell de commandes. Dans la réalité, la
fonction system crée un sous shell ou sous processus exécutant la commande
transmise en argument.
2.1.1 Syntaxe et valeur de retour de la fonction system
La fonction system considère comme argument d’entrée une chaı̂ne de
caractères indiquant la commande à exécuter. Sa syntaxe est indiquée comme
suit : system(char*) Elle retourne une valeur entière dont la signification
est :
– 127, lorsque le shell ne peut être exécuté
– -1 en cas d’erreur
Puisque la fonction system invoque un nouveau shell, elle est sujette aux limi-
tations et failles sécuritaires du shell système. Le comportement de cette fonc-
tion varie d’un environnement unix à un autre. la fonction system nécessite
l’inclusion de la librairie 3 : stdlib.h
2.1.2 Exemple d’utilisation de cette fonction
#include ¡stdlib.h>
int main()
{
int valeur retour ;
valeur retour=system(“ ls -all /”) ;
return valeur retour ;
}
Ce programme crée un sous-processus du shell qui exécute la commande “ls
-all”.
2.2 La primitive fork()
la primitive fork() permet de créer deux processus :
– le processus père
– le processus fils
la fonction fork() exige l’inclusion des librairies 4 C suivant :
3. biliothèque ou fichier d’en-tête
4. fichiers d’en-tête
Complexe Universitaire Siantou
Cycle Licence profressionnelle
Gestion des ProcessusProgrammation des processus jnouedoni@[Link]
2.2 La primitive fork() 3
1. stdlib.h
2. unistd.h
3. sys/types.h
Lorsqu’un programme en cours d’exécution comporte l’instruction fork(),
celle-ci 5 crée deux processus exécutant le même programme dans deux con-
textes différents. Ces deux processus étant distincts, ils possèdent forcément
des PID différents.
2.2.1 valeur de retour et syntaxe de la fonction fork()
La fonction fork() n’admet aucun argument d’entrée mais retourne deux
valeurs de retour. Ces valeurs de retour sont du type :pid t 6 .
La valeur de retour de la fonction fork() est nulle chez le processus fils et
non nulle chez le processus père. La valeur non nulle retournée chez le pro-
cessus père correspond au PID du processus fils. nomvariable=fork()
2.2.2 Exemples d’utilisation de la fonction fork()
L’exemple de code suivant crée 2 processus affichant les messages “je suis
le père pour l’un “ et “je suis le fils “ pour l’autre. # include <stdlib.h>
# include <unistd.h>
# include <sys/types.h>
pid t numprocessus ;
int main()
{
numprocessus=fork() ;
if (numprocessus >0)
printf(”je suis le processus père”) ;
else
printf(”je suis le processus fils”) ;
return 0 ;
}
Il est possible d’utiliser la fonction getpid() pour déterminer la valeur exacte
du numéros de chaque processus. Cette fonction permet donc à un programme
en cours d’exécution de fixer son identifiant. L’extrait de code suivant per-
met de créer deux processus père et fils affichant chacun son pid. #include
<stdlib.h>
#include <unistd.h>
5. l’instruction
6. valeur entière définie dans la bibliothèque sys/types.h
Complexe Universitaire Siantou
Cycle Licence profressionnelle
Gestion des ProcessusProgrammation des processus jnouedoni@[Link]
2.3 getpid() et getppid() 4
#include <sys/types.h>
pid t numprocessus ;
int main()
{
numprocessus=fork() ;
if (numprocessus)
{
printf(”je suis le processus père”) ;
printf(” mon pid a pour valeur :%d”, getpid()) ;
}
else
{
printf(”je suis le processus fils”) ;
printf(” mon pid a pour valeur :%d”, getpid()) ;
} return 0 ;
}
2.3 getpid() et getppid()
La primitive getppid() retourne le numéros du processus grand père d’un
processus alors que la primitive getpid() retourne le numéros du processus
parent d’un [Link], déjà décrit dans le chapitre sur la gestion des
processus, chaque processus possède un père. On obtient ainsi un arbre de
processus dont l’ancêtre est init. #include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
pid t numprocessus ;
int main()
{
numprocessus=fork() ;
if (numprocessus)
{
printf(”je suis le processus père”) ;
printf(” mon pid a pour valeur :%d”, getpid()) ;
}
else
{
printf(”je suis le processus fils”) ;
printf(” mon pid a pour valeur :%d”, getpid()) ;
printf(” le pid de mon grand-père a pour valeur :%d”, getppid()) ;
Complexe Universitaire Siantou
Cycle Licence profressionnelle
Gestion des ProcessusProgrammation des processus jnouedoni@[Link]
3 Exécution de programmes par les processus 5
} return 0 ;
}
3 Exécution de programmes par les proces-
sus
Lorsqu’un processus est crée, il hérite du même code que le programme
qui le crée. Pour établir une séparation entre le processus père et le processus
fils du point de vue code exécuté, il est posssible de faire usage des primitives
exec pour amener le fils à exécuter un autre programme que le processus
père. La famille de fonction exec regroupe diverses catégories repertoriées à
travers leur orthographe :
1. les fonctions exec dont l’orthographe contient la lettre p tel que : execvp,
execlp. Ces fonctions acceptent un nom de programme en paramètre
et recherchent ce programme dans les repertoires indiqués par la vari-
able système PATH. Les argument du programme sont fournis dans un
tableau dont chaque indice correspond à une chaı̂ne de caractères. Le
dernier indice du tableau devant avoir la valeur NULL 7 .
2. les fonctions exec dont l’orthographe contient la lettre e : execve, execle.
Ces fonctions acceptent une liste d’arguments dont la fin est indiquée
par la chaı̂ne NULL et une table de variables d’environnement comme
second argument. Chaque chaı̂ne de la liste des arguments est de la
forme variable=valeur.
3. les fonctions exec dont l’orthographe contient la lettre l : execl, execlp.
Ces fonctions admettent la fourniture des arguments sous forme d’une
liste. Chaque argument de la liste étant une chaı̂ne de caractères ou
encore pointeur sur un caractère. Le dernier élément de la liste des
arguments est l’argument null dont la valeur correspond à NULL pour
désigner une chaı̂ne vide 8
4. les fonctions exec ayant dans leur orthographe les lettres l,e et p ont
une signification combinant les explications ci-dessus
Le tableau suivant mentionne toutes les fonctions exec offertes par le langae
C
7. pointeur vide
8. En C,pour un pointeur sur une chaı̂ne de caractères, NULL désigne une chaı̂ne vide
Complexe Universitaire Siantou
Cycle Licence profressionnelle
Gestion des ProcessusProgrammation des processus jnouedoni@[Link]
3.1 primitive execvp 6
primitives format d’argument passage d’environnement recherche avec PATH
execl liste automatique non
execv tableau automatique non
execle liste manuel non
execve tableau manuel non
execlp liste automatique oui
execvp tableau automatique oui
Table 1 – liste des fonctions exec
3.1 primitive execvp
La fonction execvp, exécute un programme passé en paramètre. La liste
des arguments de ladite fonction est fournie dans un tableau de pointeur
sur des chaı̂nes de caractères. la syntaxe de cette fonction est : execvp(char*
program, char* arglist) l’argument program est une chaı̂ne de caractères qui
fournit le nom du programme à exécuter. cette fonction retourne une valeur
en cas d’erreur d’exécution. #include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
pid t numprocessus ;
int main()
{
char** tab ;
char** param ;
char* prog, prog2 ;
tab=(char**)malloc(sizeof(char)*10) ;
tab=”ps”, ”-ef” ;
param=(char**)malloc(sizeof(char)*10) ;
param=”ls”, ”-all”, ”/”, NULL ;
numprocessus=fork() ;
if (numprocessus)
{ printf(”je suis le processus père”) ;
printf(”mon pid a pour valeur :%d”, getpid()) ;
printf(”voici la liste des processus”) ;
prog=(char*)malloc(sizeof(char)*100) ;
prog=”ps” ;
execvp(”ps”, tab) ;
} else
{
Complexe Universitaire Siantou
Cycle Licence profressionnelle
Gestion des ProcessusProgrammation des processus jnouedoni@[Link]
3.2 primitive wait 7
printf(”je suis le processus fils”) ;
printf(”mon pid a pour valeur :%d”, getpid()) ;
// printf(”le pid de mon grand-père a pour valeur :%d”, getppid()) ;
prog2=(char*)malloc(sizeof(char)*100) ;
prog2=”ls” ;
execvp(”ls”, param) ;
}
return 0 ;
}
L’extrait de programme ci-dessus crée deux processus. Le processus père
liste les processus en cours d’exécution alors que le processus fils fournit la
liste des fichiers du repertoire racine. Dans ce programme, la fonction malloc
est utilisée pour reserver en mémoire centrale un espace pour conserver les
données d’une chaı̂ne de caractères. La fonction execvp permet d’exécuter
une commande à prtir du shell unix.
3.2 primitive wait
La fonction wait provoque la suspension du processus appelant cette fonc-
tion. Ainsi, si un processus père invoque cette fonction, l’exécution de ce
dernier est suspendu jusqu’à ce que l’un de ses processus fils se termine. Il
n’est pas possible de choisr le processus fils dont le père doit attendre la
terminaison.
3.2.1 syntaxe de la fonction wait
int wait(int* statusp) la fonction wait considère en entrée un pointeur
sur un entier et retourne une valeur entière. La valeur retournée peut être -1,
en cas d’erreur ou alors l’identifiant d’un processus. Pour examiner le mode
de sortie d’un processus exécuté, il est indispensable de consulter la valeur
de statusp en utilisant pour cela une des macros ou fonctions suivantes :
1. WEXITSTATUS pour extraire la valeur de retour du processus fils
2. WIFEXITED pour savoir si le processus fils s’est achevé normalement
3. WTERMSIG pour obtenir le code du signal ayant provoqué la termi-
naison du processus fils
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
pid t numprocessus ;
int main()
Complexe Universitaire Siantou
Cycle Licence profressionnelle
Gestion des ProcessusProgrammation des processus jnouedoni@[Link]
3.2 primitive wait 8
{
char** tab ;
char** param ;
char* prog, prog2 ;
tab=(char**)malloc(sizeof(char)*10) ;
tab=”ps”, ”-ef” ;
param=(char**)malloc(sizeof(char)*10) ;
param=”ls”, ”-all”, ”/”, NULL ;
numprocessus=fork() ;
if (numprocessus)
{ printf(”je suis le processus père”) ;
wait(&numprocessus) if (WIFEXITED(numprocessus) { printf(”le processus
fils s’ est normalement achevé, avec comme code de retour :%d”, WEXIT-
STATUS(numprocessus)) ; } else printf(”voici la liste des processus”) ;
prog=(char*)malloc(sizeof(char)*100) ;
prog=”ps” ;
execvp(”ps”, tab) ;
} else
{
printf(”je suis le processus fils”) ;
printf(”mon pid a pour valeur :%d”, getpid()) ;
prog2=(char*)malloc(sizeof(char)*100) ;
prog2=”ls” ;
execvp(”ls”, param) ;
}
return 0 ;
}
le langage C propose des variantes plus performantes de la fonction wait
telles que : wait3 et wait4. Ces fonctions permettente de nettoyer de manière
asynchrone le contexte d’exécution des processsus zombies.
3.2.2 Processus zombie
Normalement, un processus père attend la fin de l’exécution de ses pro-
cessus fils. L’appel de la fonction wait par un processus père ne lui permet pas
seulement d’attendre la fin de l’exécution de ses fils mais est aussi utile pour
nettoyer l’environnement d’exécution du processus fils. Lorsqu’un processus
fils s’achève alors que son père n’attend pas sa fin d’exécution, ledit processus
fils devient un processus zombie. Un processus zombie est donc un processus
qui s’est terminé sans que son contexte d’exécution n’ ait été nettoyé par
Complexe Universitaire Siantou
Cycle Licence profressionnelle
Gestion des ProcessusProgrammation des processus jnouedoni@[Link]
3.3 transmission des signaux aux processus 9
son processus père. l’extrait de code suivant produit un processus fils zombie
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
pid t numprocessus ;
int main()
{
numprocessus=fork() ;
if (numprocessus)
{
printf(”je suis le processus père”) ;
sleep(10000) ;
}
else
{
exit(0) ; } return 0 ;
}
la primitive sleep invite le père à attendre pendant 10000 ms avant de pour-
suivre son exécution. Elle ne permet pas au processus père d’attendre la
terminaison de son fils.
3.3 transmission des signaux aux processus
A partir d’un programme C, il est possible de transmettre un signal à
un processus. Pour cela, il suffit d’utiliser la primitive kill de la manière
suivante :
kill(pid t child pid,int signal)
child pid désigne l’identifiant d’un processus ; signal indique le numéro du
signal devant être transmis au processus dont l’identifiant est child pid. En
particulier, pour provoquer la terminaison d’un processus, il suffit donc de
transmettre le signal SIGTERM au processus dont on souhaite l’achèvement.
Il est important de signaler qu’avant toute utilisation de la fonction kill, il
faut inclure les bibliothèques : <signal.h >et <sys/types.h>
Complexe Universitaire Siantou
Cycle Licence profressionnelle
Gestion des ProcessusProgrammation des processus jnouedoni@[Link]
4 initiation aux techniques de communication inter-processus 10
4 initiation aux techniques de communica-
tion inter-processus
4.1 Définition
la communication inter processus ou IPC inter process communication
désigne un ensemble de techniques permettant aux processus de s’échanger
des informations. C’est aussi le transfert des données entre divers processus.
4.2 Les mécanismes de communication inter-processus
Les techniques suivantes peuvent être utilisées pour favoriser les commu-
nications inter-processus :
1. les mémoires partagées
2. les tubes ou pipes
3. les FIFO
4. les sockets
5. la technique dite Mapped Memory
4.3 les mémoires partagées
Les mémoires partagées représentent le procédé le plus simple de com-
munication inter-processus. Ici, les processus s’échangent des données en
accédant à la même zone mémoire, pour y lire ou écrire des données. Ce
mécanisme IPC est le plus rapide des techniques de communication inter-
processus. Cependant, les mémoires partagées nécessitent l’utilisation des
sémaphores comme mécanisme de synchronisation.
4.4 Mapped Memory
Le mécanisme Mapped Memory est une technique de communication in-
terprocessus permettant à plusieurs processus de s’échanger des données par
l’intermédiaire d’un fichier partagé.
4.5 Les tubes
Encore appelé pipe ou conduit, un tube est un mode de communication
interprocessus unidirectionnel. La communication est unidirectionnelle en ce
Complexe Universitaire Siantou
Cycle Licence profressionnelle
Gestion des ProcessusProgrammation des processus jnouedoni@[Link]
4.6 les FIFO 11
sens que certains processus peuvent écrire des données dans le tube pen-
dant que d’autres ne pourront que lire les données. Les processus rédacteurs
écrivent à un bout du tube et d’autres processus lisent à l’autre bout du tube
4.6 les FIFO
Les FIFO 9 ou file de message sont une variante de tubes. Les fifo sont
des tubes possédant des noms dans le système de fichiers.
4.7 les sockets
les sockets sont le mécanisme de communication inter processus le plus
évolué. Ils permettent à des processus présents sur la même machine ou des
machines distinctes de communiquer ou s’échanger des données. Les applica-
tions réseau tels que telnet, ftp, rlogin, talk ou le www exploitent le principe
de communication par socket. Un Socket est en réalité la combinaison adresse
ip et numéro de port.
Le chapitre suivant déatillera ces techniques de communication interpro-
cesssus.
9. First in First out
Complexe Universitaire Siantou
Cycle Licence profressionnelle
Gestion des ProcessusProgrammation des processus jnouedoni@[Link]