Comprendre les processus en informatique
Comprendre les processus en informatique
1 Introduction
Dans de nombreuses applications, surtout celles faisant appel aux principes Client-Serveur 1 , il est
nécessaire de dupliquer le processus serveur, à chaque fois qu’un client désire se connecter 2 . On peut faire
rapidement la manipulation en montant l’un des serveurs suivant Web, Telnet ou FTP... sur une machine et
à chaque fois qu’un client se connecte, on lance la commande ps et l’on constate qu’un nouveau processus
de même nom est lancé et occupe une place en mémoire.
Pour certains serveurs, tel le serveur Web apache, même si personne n’est connecté il y a dès le début
plusieurs processus httpd en attente de connexion. Nous aurons l’occasion de développer tout cela lors
du cours sur la Communication par Socket.
2 Rappels
— User Mode vs Kernel Mode et les espaces mémoire
Les Processus
Page 1/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
Un système d’exploitation est découpé en 2 parties : le noyau et le reste donc nous les utilisa-
teurs ! ! !
Il y a donc 2 modes de fonctionnement le mode noyau et le mode et bien pas noyau le mode des
utilisateurs
Le noyau fait l’interface entre l’utilisateur et le matériel
Si on parle d’espaces mémoire, cela veut dire qu’il y a 2 espaces mémoire celui du noyau et celui
des utilisateurs qui font
— 1Go et 3Go sur un vieux système 32 bits soit 25% pour le kernel
— 512Go (549 755 813 888) et beaucoup beaucoup sur un système 64 bits 2^64 - 2^39 = 18 446
744 073 709 551 616 - 549 755 813 888 je vous laisse le faire ?
18 446 743 523 953 737 728 soit 0,000000000000056% pour le kernel
— Définition : Un processus fournit à un instant t l’image de l’état d’avancement de l’exécution d’un
programme.
Le programme est le produit d’une compilation donnant un objet inerte correspondant au contenu
d’un fichier.
— Constitution : Un processus est constitué du programme qu’il est en train d’exécuter, de l’ensemble
des données que ce même programme manipule et d’un ensemble d’informations dont le SE à besoin
pour prendre en compte ce processus.
Tout cela constitue le contexte d’exécution :
— les valeurs des registres du processeur correspondant à l’état d’avancement de l’exécution,
— pile d’exécution,
— liens avec l’utilisateur,
— le système E/S etc...
— pid processus identificator : un processus possède un identificateur qui lui est propre et qui est une
valeur comprise entre 1 et 32767, le processus père de tous les autres est le processus 1, Init . Ce
n’est plus toujours vrai depuis SystemD ! ! ! voir plus loin ! ! !
Pour connaitre la valeur max de processus, donc pid : sysctl kernel.pid_max (attention avant
c’était sysctl kern.pid_max manque le el au kernel ! ! !)
Elle doit vous renvoyer la valeur : kernel.pid_max = 32768
Cette valeur est trouvée dans le répertoire /proc/sys/kernel le fichier pid_max
— Affichage des processus : La commande ps affiche la liste des processus en cours d’exécution,
ceux exécutés par l’utilisateur lui même, ceux exécutés par les autres utilisateurs et tous ceux du
système. Exemple : ps -auf, ps jf, ps -edfl
Les Processus
Page 2/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
X mort pas besoin de l’expliquer... et de toute manière vous ne pouvez pas le voir ,
Pour rire un peu comme dans cet Amphi, un seul Processus est R (Le prof) tous les autres sont S (
Vous !)
Les Processus
Page 3/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
— Le commutation de contexte : Sur un ordinateur, vous n’avez qu’un seul µP qui est constitué de
registres. Ces registres contiennent des données représentant le processus en cours d’exécution (la
taille mémoire utilisée, le compteur ordinal...).
Quand le système décide de passer un processus P1 à un processus P2, il faut faire un changement
de contexte, donc sauvegarder le contexte du processus P1 et récupérer le contexte du processus
P2. Ceci à un cout au niveau des temps d’exécution. Oui oui un système multitâches est plus lent
qu’un système monotâche !
— Le contexte d’un processus : l’ensemble des données qui permettent de reprendre l’exécution
d’un processus interrompu.
Le contexte d’un processus est l’ensemble de
1. son état
2. son mot d’état : en particulier
(a) La valeur des registres actifs
(b) Le compteur ordinal
3. les valeurs des variables globales statiques ou dynamiques
4. son entrée dans la table des processus
5. sa zone u (u pour user)
6. Les piles user et system
7. les zones de code et de données.
Le noyau et ses variables ne font partie du contexte d’aucun processus !
L’exécution d’un processus se fait dans son contexte. Quand il y a changement de processus cou-
rant, il y a réalisation d’une commutation de mot d’état et d’un changement de contexte. Le noyau
s’exécute alors dans le nouveau contexte.
— La table des Processus et zone u : Tous les processus sont associés à une entrée dans la table
des processus appartenant au noyau. De plus, le noyau alloue pour chaque processus une struc-
ture appelée zone u, qui contient des données privées du processus, uniquement manipulables par
le noyau. La table des processus permet d’accéder à la table des régions par processus qui per-
met d’accéder à la table des régions. Ce double niveau d’indirection permet de faire partager des
régions. Dans l’organisation avec une mémoire virtuelle, la table des régions est matérialisée logi-
quement dans la table de pages. Les structures de régions de la table des régions contiennent des
informations sur le type, les droits d’accès et la localisation (adresses en mémoire ou adresses sur
disque) de la région. Seule la zone u du processus courant est manipulable par le noyau, les autres
sont inaccessibles. L’adresse de la zone u est placée dans le mot d’état du processus.
— Espace d’adressage virtuel d’un processus
Le fait qui consiste à attribuer une zone mémoire pour chaque donnée du programme source s’ap-
pelle le processus d’allocation mémoire.
Le compilateur doit être capable de substituer chaque référence à une variable par son
adresse. Cela s’appelle le processus de substitution. Par exemple la référence à un élément de
tableau, champs de structure, fonction virtuelle, etc.
L’espace d’adressage virtuel d’un processus est subdivisé en régions qui sont Code, Data static,
Datas dynamiques, les arguments, Pile et le Tas.
Zone u Code ou texte static globale Pile → dynamiques ← Tas les arguments
— Zone u : Informations sur le processus
— Code ou Texte : Instructions
— Les zones contenant le code, les données statiques et globales ont des tailles connues
— Le tas et la pile s’accroissent et rétrécissent durant l’exécution du programme. La pile : C’est
une pile de structures de pile qui sont empilées et dépilées lors de l’appel ou le retour de fonction.
Le pointeur de pile, un des registres de l’unité centrale, indique la profondeur courante de la pile.
ESP-EBP sur x86.
Les Processus
Page 4/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
La plupart des fichiers sont en lecture seule, normal ils appartiennent au noyau et même le root n’y a pas
accès ! ! !
Mais quelques uns (fichiers) permettent la modification de variables du noyau. Comme nous avons fait
un peu de réseau et que je vous ai parlé d’IPv6... si vous voulez que votre noyau ne parle pas l’IPv6 et bien
il suffit de lancer les 4 commandes suivantes :
1. Désactiver ipv6 pour toutes les interfaces : sysctl -w [Link].disable_ipv6=1
2. Désactiver l’auto configuration pour toutes les interfaces : sysctl -w [Link]=0
3. Désactiver ipv6 de la configuration par défaut : sysctl -w [Link].disable_ipv6=1
4. Désactiver l’auto configuration par défaut : sysctl -w [Link]=0
Ceci à chaud et si on veut que cela soit définitif et bien il suffit d’écrire ces instructions en dur dans
le fichier /etc/[Link] et de lancer la commande sysctl -p
Rien ne vous empêche de le faire pour Ipv4 et de désactiver la réponse au ping vous savez la couche 3 du
modèle OSI qui soit disant ne marche plus alors que les couches 7 telles http sont accessibles ,
sysctl -w net.ipv4.icmp_echo_ignore_all=1 renvoie net.ipv4.icmp_echo_ignore_all = 1
Puis un ping localhost renvoie rien ,
Bon pourquoi cette partie, tout cela pour vous persuader que le répertoire /PROC n’est pas que le
répertoire de Processus mais un image de tout ce que connait le noyau ! ! !
Et comme une image ça ne prend pas de place et bien la taille occupée dans le SGF par ce répertoire
/proc est NULLE ! ! ! !
La preuve un du -h renvoie que des 0 ! ! !
Autre preuve et TP à faire ! ! ! Éteindre et aller voir ce qu’il y a dans dans ce répertoire et bien il n’y
a rien. Comment faire cela et bien c’est comme pour voir si la lumière est éteinte dans le réfrigérateur
quand la porte est fermé. Je vous laisse trouver la solution qui existe ! ! !
et il est lié à
# mount | grep proc
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
Bon revenons au répertoire /proc et ce qui nous intéresse des processus. Faisons un ls de son contenu,
nous obtenons en “gros”
Tous les beaux chiffres et nombres en bleu sont des répertoires et la valeur représente les PID des
processus en cours.
Ces répertoires sont appelés répertoires de processus car ils font référence à un ID de processus et
contiennent des informations se rapportant à ce dernier. Le propriétaire et le groupe de chaque répertoire
de processus prennent la valeur de l’utilisateur qui exécute le processus.
Lorsque le processus est terminé, son répertoire de processus /proc/ disparaît.
Chaque répertoire de processus contient (liste non exhaustive ! !) les lignes suivantes :
cmdline Contient la commande émise au début du processus.
cwd Représente un lien symbolique vers le répertoire de travail courant pour ce processus.
environ Fournit une liste des variables d’environnement du processus. La variable d’environnement
est indiquée en majuscule et la valeur en minuscule.
exe Représente un lien symbolique vers le fichier exécutable de ce processus.
fd Représente un répertoire contenant tous les descripteurs de fichiers pour un processus donné.
Ces derniers sont fournis sous forme de liens numérotés :
maps Contient une liste des topologies de mémoire vers les divers fichiers exécutables et les fichiers
bibliothèques associés à ce processus.
Selon la complexité du processus, ce fichier peut être relativement long.
mem Représente la mémoire occupée par le processus. Ce fichier ne peut pas être lu par l’utilisa-
teur ! ! ! Tiens pourquoi ?
cat : mem : Erreur d’entrée/sortie
root Représente un lien vers le répertoire root du processus.
Les Processus
Page 5/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
Lancez la commande ps -axjf et vous obtenez quelque chose un peu identique mais sous une forme.
Vous pouvez constater une arborescence avec 2 racines, celle des processus ayant pour père kthreadd et
la seconde
ayant pour père init
Une autre commande qui appartient au paquet psmisc contenant les utilitaires qui utilisent le système de
fichiers virtuels /proc
Les Processus
Page 6/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
i n t main ( ) {
5 i n t valeur_de_retour ;
p r i n t f ( " Exécution de ps avec system \ n" ) ;
7 valeur_de_retour = system ( "ps auf " ) ;
p r i n t f ( " valeur de retour %d \ n" , valeur_de_retour ) ;
9 return valeur_de_retour ;
}
6 Créer un processus
Un fork ou une fourchette en anglais. En informatique on parle souvent de fork, par exemple libre
office est un fork d’Openoffice, cela veut dire qu’il en est une copie ?
Autre exemple : MariaDB est un fork de MySQL d’Oracle
[Link]
...
Donc : Un nouveau processus peut-être créé en appelant la primitive fork .
#include <unistd.h>
pid_t fork(void)
Cet appel système copie le processus actif en insérant dans la table des processus une nouvelle entrée
dotée des mêmes attributs, ce nouveau processus est quasiment identique à l’original, il exécute le même
code mais avec ses propres espaces de données, environnement et descripteurs de fichiers.
L’appel fork dans le père renvoie le PID du processus fils. Celui-ci continue de s’exécuter comme l’original,
à la différence que fork renvoie 0 dans le processus fils.
Les Processus
Page 7/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
5 i n t main ( ) {
pid_t pid ;
char *message ;
int n;
p r i n t f ( "Lancement du fork \ n" ) ;
10 pid=fork ( ) ;
switch ( pid ) {
=
case 1:
perror ( "echec de fork " ) ;
return 1;
15 case 0:
message = " le f i l s " ;
n=10;
break ;
default :
20 message = " le papa" ;
L’utilisation typique de l’appel fork est la sui- n=3;
vante : break ;
}
1. pid_t pid = fork() ; ==
for ( ; n>0; n ){
25 p r i n t f ( "%s , pid : %i et papa : %i \ n" , \
2. if pid (pid==0) {
message, getpid ( ) , getppid ( ) ) ;
3. /* Instructions du fils */ } sleep (1) ;
}
4. else if (pid >0) { // pid du fils <>0 return 0;
30 }
5. /* Instructions du père */ }
6. else {
7. /* Erreur (Instruction du père) */ }
Le primitive fork renvoie -1 en cas d’échec souvent en raison du nombre limité de processus fils qu’un
père peut posséder (CHILD_MAX), un manque d’espace empêchant la création d’une entrée dans la table
des processus ou une mémoire virtuelle insuffisante.
Dans l’exemple précédent, le programme s’exécute comme 2 processus, le père affiche 3 messages et
le fils 8. Ce programme ne fonctionne pas correctement, pourquoi ?
Réponse :
7 Le zombie
Après nous verrons les processus démons qui n’ont rien à voir avec les processus zombies ,.
Tout processus se terminant passe dans l’état zombie et y reste tant que son père n’a pas pris connais-
sance de sa terminaison.
Les Processus
Page 8/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
Ceci est dû au faite que tout processus se terminant possède une valeur de retour à laquelle son père
peut accéder.
Mais contrairement à la fonction appelante qui est bloquée par la fonction appelée, dans le cas des
processus, le père et le fils peuvent se dérouler en parallèle. Le système fourni donc au père un moyen lui
permettant d’accéder au code de retour du fils terminé. Il y a aussi l’envoie au père du signal SIGCHLD 3 .
Les seules informations maintenues dans le bloc de contrôle d’un processus zombie sont :
— Son code de retour ;
— Ses temps d’exécution dans les 2 modes (kernel et user) ; La commande time les donne !
— Son identité et celle de son père.
=
/ / Mon nom est : make zombie ! ! !
#include <stdio . h>
#include <s t d l i b . h>
#include <unistd . h>
5 i n t main( i n t argc , char ** argv ){
Après avoir compilé ce programme et l’avoir lancé, listez les processus en cours d’exécution à l’aide
de la commande ps -e -o pid, ppid,stat,cmd | grep zombie
Elle dresse la liste des identifiants de processus, de processus père, de leur statut et de la ligne de
commande du processus.
Observez qu’en plus du processus père make-zombie, un autre processus make-zombie est affiché. Il
s’agit du processus fils ; notez que identifiant de son père est celui du processus make-zombie principal.
Le processus fils est marqué comme <defunct > et son code de statut est Z pour zombie.
Que se passe-t-il lorsque le programme principal de make-zombie se termine sans appeler wait ?
Le processus zombie est-il toujours présent ?
Non - relancez ps et notez que les 2 processus make-zombie ont disparu.
Lorsqu’un programme se termine, un processus spécial hérite de ses fils, le programme init 4 , qui
s’exécute toujours avec un identifiant de processus valant 1 (il s’agit du premier processus lancé lorsque
Linux démarre).
3. Voir le cours sur les signaux.
4. Si vous êtes sur un système... avec INIT
Les Processus
Page 9/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
8 L’orphelin
Si on reprend le code précédent générant un processus Zombie mais que cette fois-ci c’est le père
qui se termine et quitte sans attendre son fils, alors le fils devient un orphelin et il est “adopté” par le
Processus INIT
=
/ / Mon nom est : make orphelin ! ! !
2 #include <stdio . h>
#include <s t d l i b . h>
#include <unistd . h>
i n t main( i n t argc , char ** argv ){
Après avoir compilé ce programme et l’avoir lancé, listez les processus en cours d’exécution à l’aide
de la commande ps -e -o pid, ppid,stat,cmd | grep orphelin
On obtient ceci
On peut constater qu’au début le père est bien le père enuite le père est le Processus de PID 1 soit
Init !
9 Les Daemons
Après avoir étudié les processus zombies qui n’ont rien à voir avec les processus démons, étudions ces
derniers,.
Après son chargement, le kernel lance le programme initial qui gère le reste du démarrage : initiali-
sation du système, lancement d’un programme de connexion...
Il va également se charger de lancer les démons. Un démon (du terme anglais daemon) est un
processus qui est constamment en activité et fournit des services au système.
Remarque : vous avez surement appris que le premier processus est le processus init dont le PID est
1... 5
Si oui, et bien il va falloir utiliser votre systemd (D comme... Daemon et non l’autre... !)
Depuis quelques années déjà, Init n’est plus utilisé et est obsolète pour lancer les daemons qui appar-
tiennent au noyau (mode kernel vs mode user) presque tout comme on en doit plus utiliser ifconfig
mais ip addr
Les Processus
Page 10/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
Si vous voulez plus d’informations à ce sujet, je vous invite à lire un de mes supports de cours (mis sur
le site et que je ne vais pas avoir le temps de vous expliquer...), quelques pages et/ou aller sur cette page
du site Linuxfr
[Link]
Bon revenons au processus Daemon
Nous n’aurons pas le temps en TP de développer un processus Daemon, mais lire le code et le com-
prendre est intéressant.
Je vous invite à lire cette page : [Link]
Je m’en suis inspiré et j’ai modifié le code de manière à ne plus avoir de warning.
/ * UNIX Daemon Server Programming Sample Program
2 Levent Karakas <levent at mektup dot at> May 2001
To =
compile : cc o exampled examped. c
To run : . / exampled
To = =
test daemon: ps ef | grep exampled ( or ps aux on BSD systems )
7 To test log : =
t a i l f /tmp/ exampled . log
To =
test signal : k i l l HUP ‘ cat /tmp/ exampled . lock ‘
To terminate : k i l l ‘ cat /tmp/ exampled . lock ‘
*/
FILE * l o g f i l e ;
l o g f i l e=fopen ( filename , "a" ) ;
i f (! logfile )
return ;
32 f p r i n t f ( l o g f i l e , "%s \ n" ,message) ;
fclose ( l o g f i l e ) ;
}
void daemonize ( ) {
int i , lfp ;
52 char s t r [ 1 0 ] ;
i f ( getppid ( )==1) return ; / * already a daemon * /
i=fork ( ) ;
i f ( i <0) e x i t (1) ; / * fork error * /
i f ( i >0) e x i t (0) ; / * parent e x i t s * /
57 / * child (daemon) continues * /
setsid ( ) ; / * obtain a new process group * /
==
for ( i=getdtablesize ( ) ; i>=0; i ) close ( i ) ; / * close a l l descriptors * /
i=open( " / dev / null " ,O_RDWR) ; dup( i ) ; dup( i ) ; / * handle standart I /O * /
umask(027) ; / * set newly created f i l e permissions * /
Les Processus
Page 11/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
77 i n t main( void ){
daemonize ( ) ;
while (1) sleep (1) ; / * run * /
return 0;
}
return ( code_de_retour ) ;
}
11 Héritage
Un processus hérite d’un grand nombre d’attributs de son père. Il n’hérite pas des attributs suivants :
— Un identification unique PID ;
— L’identification de son processus père ;
Les Processus
Page 12/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
i n t main ( ) {
9 char ch[ 1 6 ] ;
i n t desc ;
desc=open( " f i c h i e r " , O_RDWR, 0) ;
i f ( fork ( )==(pid_t ) 0) { / / dans le f i l s
write ( desc , " f i s t o n " , 6) ;
14 sleep (2) ;
read ( desc , ch , 4) ;
p r i n t f ( "Chaine lue f i l s : %s \ n" , ch ) ;
}
else { / / dans le père
19 sleep (1) ;
read ( desc , ch , 2) ;
p r i n t f ( "Chaine lue papa : %s \ n" , ch ) ;
write ( desc , "papa" , 4) ;
}
24 return 0;
}
Le code suivant permet de constater que le fils hérite des attributs : les propriétaires, le répertoire et la
valeur de nice
i n t main ( ) {
char buf [1024]; / / Pour le répertoire de t r a v a i l * /
struct tms temps ; / * Pour les nombres de c l i c s * /
10 int i ;
nice (10) ;
for ( i =0; i <10000000; i++); / / Une boucle consommatrice de CPU
i f ( fork ( )==(pid_t ) 0){ / / f i l s
p r i n t f ( " \ nCaractéristiques du f i l s \ n" ) ;
15 p r i n t f ( " uid=%d euid=%d gid=%d egid=%d \ n" , getuid ( ) , geteuid ( ) , getgid ( ) , getegid ( ) ) ;
p r i n t f ( " Répertoire de t r a v a i l : %s \ n" , getcwd( buf ,1024) ) ;
p r i n t f ( " nice : %d \ n" , nice (0)+20) ;
times ( &temps ) ;
p r i n t f ( " Clics en mode u t i l i s a t e u r %d \ n" , temps . tms_utime ) ;
20 p r i n t f ( " Clics en mode systeme %d \ n" , temps . tms_stime ) ;}
else{ / / papa
sleep (5) ; / * Le père s ’ exécutera après le f i l s * /
p r i n t f ( " \ nCaractéristiques du père \ n" ) ;
p r i n t f ( " uid=%d euid=%d gid=%d egid=%d \ n" , getuid ( ) , geteuid ( ) , getgid ( ) , getegid ( ) ) ;
25 p r i n t f ( " Répertoire de t r a v a i l : %s \ n" , getcwd( buf ,1024) ) ;
p r i n t f ( " nice : %d \ n" , nice (0)+20) ;
times ( &temps ) ;
p r i n t f ( " Clics en mode u t i l i s a t e u r %d \ n" , temps . tms_utime ) ;
p r i n t f ( " Clics en mode systeme %d \ n" , temps . tms_stime ) ;}
30 }
Les Processus
Page 13/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
12 Un peu plus
12.1 Vfork
Il existe une variante à l’appel système fork(), c’est vfork(), cet appel système permet lui aussi de créer
un fils, mais le père est bloqué pendant l’exécution du fils. Vous me direz à quoi cela peut servir ?, je vais
y répondre...
Cela permet d’aller beaucoup plus vite, car vfork() sert à créer un nouveau processus sans effectuer de
copie de la table des pages mémoire du processus père et le code est partagé avec plusieurs applications.
Ce principe est surtout utilisé dans les systèmes embarqués où l’empreinte mémoire est beaucoup plus
faible. on remplace la glibc par une uClibc qui est 5 fois plus petite, ce qui remplace Linux par uClinux
qui fonctionne sur la majeur partie des systèmes embarqués.
Le code qui suit montre une utilsation de cette primitive vfork(). Dans ce code si vous remplacez
simplement la primitive vfork () de la ligne 6 par un simple fork, le programme ne se comporte plus de la
même façon.
i n t n ; / / une variable globale
i n t main ( ) {
i n t pid ;
p r i n t f ( "L ’@ v i r t u e l l e de n dans le père %p \ n" , &n) ;
5 n=0;
switch ( pid=vfork ( ) ){
=
case 1:
perror ( "echec de vfork " ) ;
e x i t (2) ;
10 case 0: / / le f i l s
p r i n t f ( "L ’@ v i r t u e l l e de n dans le f i l s %p \ n" , &n) ;
n=1;
p r i n t f ( " f i l s s ’ endort 10s et le père est bloqué \ n" ) ;
sleep (10) ;
15 p r i n t f ( "Terminaison du f i l s \ n" ) ;
_ e x i t (0) ;
default : / / le père
sleep (1) ; / / afin que le père s o i t élu après le f i l s
p r i n t f ( " Reprise d ’ execution du père \ n" ) ;
20 n++; / / n vaut alors 2 car le f i l s la mis à 1 . . .
p r i n t f ( " Valeur de n dans le père %d \ n" ,n) ;
e x i t (0) ; }}
12.2 Thread
Il existe une extension de ce modèle de processus, ce sont les processus léger (thread ) en opposi-
tion aux processus lourd. Un processus classique est constitué d’un espace d’adressage avec un seul fil
d’exécution constitué du compteur ordinal et une pile d’exécution.
dans le domaine des processus léger, on ne dispose que d’un seul espace d’adressage admettant plu-
sieurs fils (pas le fiston, le fil comme celui à coudre...) d’exécution et chacun de ces fils d’exécution est
appelé thread , processus léger ou activités possédant chacun un compteur ordinal et une pile d’exé-
cution privée. L’entité contenant les différents fils d’exécution est appelé processus ou acteur.
Les avantages sont :
— la commutation de contexte est très allégées. Le processeur n’a besoin que e changer de pile et de
compteur ordinal, le contexte mémoire reste inchangé ;
— l’opération de création d’un nouveau fil d’exécution est elle aussi plus légère puisqu’il n’est plus
nécessaire de dupliquer complètement l’espace d’adressage du processus père.
Les 2 sources ci-dessous permettent de comparer les 2 mécanismes, processus et thread
Les Processus
Page 14/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
— Un thread peut endommager les données d’autres threads du même processus car les threads par-
tagent le même espace mémoire et leurs ressources. Par exemple, une écriture sauvage en mémoire
via un pointeur non initialisé au sein d’un thread peut corrompre la mémoire d’un autre thread. Un
processus corrompu par contre, ne peut pas agir de cette façon car chaque processus dispose de sa
propre copie de l’espace mémoire du programme.
— Copier le contenu de la mémoire pour un nouveau processus a un cout en performances par rapport
à la création d’un nouveau thread. Cependant, la copie n’est effectuée que lorsque la mémoire est
modifiée, donc ce cout est minime si le processus fils ne fait que lire la mémoire.
— Les threads sont utilisés pour les programmes qui ont besoin d’un parallélisme finement contrôlé.
Par exemple, si un problème peut être décomposé en plusieurs tâches presque identiques, les
threads peuvent être un bon choix. Les processus sont utilisés pour des programmes ayant besoin
d’un parallélisme plus grossier.
— Le partage de données entre des threads est trivial car ceux-ci partagent le même espace mémoire.
Le partage de données entre des processus nécessite l’utilisation de mécanismes IPC que nous
allons voir plus tard.
/ / processus_thread_exemple . c
#include <stdio . h>
3 #include <unistd . h>
i n t i ; / / Variable globale
i n t main ( ) {
pid_t pid ;
8 i =0;
pid=fork ( ) ;
/ / thread_exemple . c
2 #include <stdio . h>
#include <pthread . h>
i n t i ; / / Variable globale
void addition ( ) {
7 i = i + 10;
p r i n t f ( " hello , thread f i l s valeur de i :%d \ n" , i ) ;
i = i + 20;
p r i n t f ( " hello , thread f i l s valeur de i :%d \ n" , i ) ;
}
12 i n t main ( ) {
pthread_t num_thread ;
i =0;
i f ( pthread_create(&num_thread , NULL,
( void * ( * ) ( ) ) addition , NULL) == 1) =
17 perror ( "problème pthread_create \ n" ) ;
i = i + 1000;
p r i n t f ( " hello , thread principal valeur de i :%d \ n" , i ) ;
i = i + 2000;
p r i n t f ( " hello , thread principal valeur de i :%d \ n" , i ) ;
22 pthread_join (num_thread , NULL) ;
return 0;}
= =
/ / à compiler avec gcc Wall lpthread thread_exemple . c
Les Processus
Page 15/16
Auteur : Pascal Fougeray UFR Science, L2 SYS : 2022
13 Conclusion
Écrire une application multiprocessus, ce n’est pas si “difficile” que cela, il suffit de bien connaitre les
principes et de les appliquer avec rigueur. Il n’existe pratiquement plus d’application digne de ce nom
n’utilisant pas ces mécanismes, surtout si vous utilisez un système d’exploitation multitâches.
Nous allons voir dans les prochains cours comment faire communiquer ces processus, leur envoyer des
signaux et les utiliser dans la programmation Client/Serveur et les faire communiquer à l’aide de socket.
Les Processus
Page 16/16