CoursSE 4
CoursSE 4
Cours 4
Sections critiques, Threads et variables de condition
Thierry Hamon
Bureau L2-316
Institut Galilée - Université Paris 13
&
LISN - Université Paris-Saclay
[email protected]
https://perso.limsi.fr/hamon/Teaching/P13/SE-INFOA1-2023-2024/
INFOA1 - SE
1/107
Plan
2/107
Exclusion mutuelle et section critique
Objectif :
exécution en parallèle de codes différents
protection de l’accès à une section critique
Section critique :
zone de code accessible qu’à un seul processus à la fois
Plan :
4 propriétés assurant la protection d’une SC et le bon
fonctionnement d’un système parallèle
Solution de Peterson
Solutions matérielles
Problèmes classiques
3/107
Exclusion mutuelle et section critique
4/107
Exclusion mutuelle et section critique
5/107
Exclusion mutuelle et section critique
Remarque
le système n’est pas déterminé
il y peut y avoir une perte d’information en raison de la
non-atomicité des opérations de crédit et de débit
Solution :
mise en place des mécanismes de contrôle de partage en
assurant l’atomicité des actions sur des variables partagées
6/107
Exclusion mutuelle et section critique
Solutions logicielles :
Seules solutions applicables dans tout environnement
Schéma type :
Segment de code qui constitue la section critique (SC)
Contraindre l’accès à la section critique par un seul processus à
la fois
Encadrement/protection de la SC par
une section d’entrée (SE)
une section de sortie (SS)
7/107
Exclusion mutuelle et section critique
Schéma type
8/107
Exclusion mutuelle et section critique
Solution : Essai 1
Code de P1 Code de P2
1 while (1) { 1 while (1) {
<SR1> <SR2>
3 while ( in 2 ) ; 3 while ( in 1 ) ;
in 1 = 1; in 2 = 1;
5 <SC1 > 5 <SC2>
in 1 = 0; in 2 = 0;
7 } 7 }
9/107
Exclusion mutuelle et section critique
Essai 1 – Commentaires
10/107
Exclusion mutuelle et section critique
Propriété 1
Propriété
Condition d’exclusion mutuelle : au plus un processus exécute sa
section critique.
11/107
Exclusion mutuelle et section critique
Solution : Essai 2
Code de P1 Code de P2
1 while (1) { while (1) {
<SR1> 2 <SR2>
3 w h i l e ( t o u r == 2 ) ; w h i l e ( t o u r == 1 ) ;
<SC1> 4 <SC2>
5 tour = 2; tour = 1;
} 6 }
12/107
Exclusion mutuelle et section critique
Essai 2 – Commentaires
13/107
Exclusion mutuelle et section critique
Propriété 2
Propriété
Condition de progression : seuls les processus qui ne sont pas en
SR peuvent contribuer à empêcher un processus d’entrer en SC.
14/107
Exclusion mutuelle et section critique
Solution : Essai 3
Code de P1 Code de P2
while (1) { while (1) {
2 <SR1> 2 <SR2>
in 1 = 1; in 2 = 1;
4 while ( in 2 ) ; 4 while ( in 1 ) ;
<SC1> <SC2>
6 in 1 = 0; 6 in 2 = 0;
15/107
Exclusion mutuelle et section critique
Essai 3 – Commentaires
Ce programme assure l’exclusion mutuelle :
par exemple, si P1 est dans SC1 , alors in1 est à 1
entre l’instruction in1 = 1 et le début de SC1 , on a eu in2 à 0,
donc, à ce moment là, P2 était en section restante (SR2 )
Alors P2 n’a pas pu, ensuite, aller plus loin que while (in1 ) :
en effet, in1 est à 1 tant que P1 n’est pas sorti de la SC1
Alors, P2 n’est pas en SC2
Il assure la progression :
si P2 est en SR, in2 = 0 et P1 peut entrer en SC1
Mais on voit arriver un nouveau problème :
si P1 commute juste après in1 = 1,
puis P2 exécute in2 = 1
while (in1 ) . . .
nouvelle commutation revenant à P1 qui exécute while (in2 )
...
→ Nous obtenons un blocage du système.
16/107
Exclusion mutuelle et section critique
Propriété 3
Propriété
Condition de non blocage : l’un au moins des processus en
attente de sa SC doit pouvoir y entrer.
17/107
Exclusion mutuelle et section critique
Propriété 4
18/107
Exclusion mutuelle et section critique
Solution de Peterson
On utilise
Une variable tour totalement partagée
une variable in_i (partagée en lecture) manipulée dans
chaque processus Pi
Code de P1 Code de P2
while (1) { 1 while (1) {
2 <SR1> <SR2>
in 1 = 1; 3 in 2 = 1;
4 tour = 2; tour = 1;
w h i l e ( i n 2 && t o u r == 2 ) ; 5 w h i l e ( i n 1 && t o u r == 1 ) ;
6 <SC1> <SC2>
in 1 = 0; 7 in 2 = 0;
19/107
Exclusion mutuelle et section critique
Solution de Peterson
Exclusion mutuelle
si P1 est en SC1 à l’instant t,
il a passé le while à l’instant t0 < t avec in2 == 0 ou tour == 1
Entre t0 (compris) et t, on a aussi in1 == 1
si in2 == 0 en t0 , P2 est en section restante en t0
Si il a atteint son while (in1 && tour == 1) en t1 > t0 ,
tant que P1 n’est pas sorti de sa section critique SC1 ,
in1 vaut 1 (affecté seulement par P1 )
tour vaut 1 (affecté par P2 juste avant t1 )
donc P2 ne peut entrer en section critique
si tour == 1 en t0 ,
tour ayant été mis à 2 par P1 en t0′ < t0 ,
il a été mis à 1 par P2 en t1′ tel que : t0′ < t1′ < t0 .
Après t1′ , tour est à 1 et in1 à 1,
donc P2 ne peut franchir son while sans que l’un ait changé, ce qui
ne se produit que lorsque P1 sort de SC1 .
20/107
Exclusion mutuelle et section critique
Solution de Peterson
Progression
si P2 est en SR,
alors in2 == 0
donc le test du while est faux pour P1 qui peut progresser
vers sa SC.
21/107
Exclusion mutuelle et section critique
Solution de Peterson
Absence de blocage
s’il y a un blocage,
P1 et P2 sont tous les deux en train d’exécuter leur boucle
while respective,
donc tour == 1 et tour == 2 (pas forcément
simultanément) ;
or aucune instruction ne permet de changer la valeur de tour
dans la boucle,
d’où la contradiction.
22/107
Exclusion mutuelle et section critique
Solution de Peterson
Attente bornée
23/107
Exclusion mutuelle et section critique
Solution de Peterson
Remarques
24/107
Exclusion mutuelle et section critique
Masquage d’interruption
Test And Set
Swap
25/107
Exclusion mutuelle et section critique
Solution active
qu’en mode système
c’est-à-dire inaccessible aux utilisateurs
et pour des portions brèves de routines
26/107
Exclusion mutuelle et section critique
27/107
Exclusion mutuelle et section critique
28/107
Exclusion mutuelle et section critique
29/107
Exclusion mutuelle et section critique
30/107
Exclusion mutuelle et section critique
31/107
Exclusion mutuelle et section critique
32/107
Exclusion mutuelle et section critique
Synchronisation, coordination
Les sémaphores - Origine (Dijkstra)
Définition
un sémaphore S est une variable entière à laquelle on ne peut
accéder qu’au travers de deux instructions insécables P (pour
proberen - Tester) et V (pour verhoggen - Incrémenter).
P(S) : if (S ≤ 0) P(S) ; else S– ;
V(S) : S++
33/107
Exclusion mutuelle et section critique
Synchronisation, coordination
Les sémaphores - Origine (Dijkstra)
34/107
Exclusion mutuelle et section critique
Emploi du sémaphore
35/107
Exclusion mutuelle et section critique
36/107
Exclusion mutuelle et section critique
Rendez-vous
Deux processus P et P’ exécutent séquentiellement
respectivement
P = C_1; C_2; ...; C_i; ...; C_m
et
P’ = D_1; D_2; ...; D_j; ...; D_n
On crée deux sémaphores rdv_i, initialisé à 0
semaphore rdv_1 = rdv_2 = 0 ;
parbegin P | P’ parend ;
P P’
C1 ; D1 ;
... ...
Ci ; Dj−1 ;
V( rdv1) ; P( rdv1) ;
P( rdv2) ; V( rdv2) ;
Ci+1 ; Dj ;
... ...
Cm ; Dn ;
37/107
Exclusion mutuelle et section critique
38/107
Exclusion mutuelle et section critique
Limites
39/107
Exclusion mutuelle et section critique
Problèmes classiques
Producteur(s)/Consommateur(s)
Lecteur(s)/Rédacteur(s)
Le problème des philosophes
40/107
Exclusion mutuelle et section critique
Producteur(s)/Consommateur(s)
41/107
Exclusion mutuelle et section critique
Fonctionnement
42/107
Exclusion mutuelle et section critique
Producteur(s)/Consommateur(s)
Solution
43/107
Exclusion mutuelle et section critique
Lecteur(s)/Rédacteur(s)
44/107
Exclusion mutuelle et section critique
Lecteur(s)/Rédacteur(s)
Solution 1
45/107
Exclusion mutuelle et section critique
Lecteur(s)/Rédacteur(s)
Solution 1
semaphore lecteur = 1
semaphore redacteur = 1
entier Nblect = 0
Code du lecteur Code du rédacteur
while (1) { 1 while (1) {
2 P( l e c t e u r ) ; P( r e d a c t e u r ) ;
Nblect = Nblect + 1;
3 LectureEtEcriture ();
4 i f N b l e c t == 1 t h e n
P( r e d a c t e u r ) V( r e d a c t e u r ) ;
6 V( l e c t e u r ) ; 5 }
Lectures ();
8 P( l e c t e u r ) ;
Nblect = Nblect − 1;
10 i f N b l e c t == 0 t h e n
V( r e d a c t e u r )
12 V( l e c t e u r ) ;
}
46/107
Exclusion mutuelle et section critique
Lecteur(s)/Rédacteur(s)
Solution 1
47/107
Exclusion mutuelle et section critique
Lecteur(s)/Rédacteur(s)
Solution 2
48/107
Exclusion mutuelle et section critique
Lecteur(s)/Rédacteur(s)
Solution 2
semaphore lecteur = 1; semaphore fifo = 1;
semaphore redacteur = 1; entier Nblect = 1;
49/107
Exclusion mutuelle et section critique
50/107
Exclusion mutuelle et section critique
source : http://www.iro.umontreal.ca/~pift1025/H08/
51/107
Exclusion mutuelle et section critique
52/107
Exclusion mutuelle et section critique
53/107
Exclusion mutuelle et section critique
54/107
Exclusion mutuelle et section critique
Code du Philosophei
1 while (1) {
penser ()
3 p r e n d r e b a g u e t t e [ i ] e t b a g u e t t e [ ( i +1)%5]
manger ( )
5 r e n d r e b a g u e t t e [ i ] e t b a g u e t t e [ ( i +1)%5]
}
55/107
Exclusion mutuelle et section critique
Commentaires :
problème : Les philosophes peuvent mourir de faim si tous les
philosophes prennent leur baguette droite en même temps
→ ils attendent tous leur baguette gauche !
Les solutions suivantes résolvent ce problème
56/107
Exclusion mutuelle et section critique
57/107
Exclusion mutuelle et section critique
58/107
Exclusion mutuelle et section critique
59/107
Exclusion mutuelle et section critique
To be continued...
60/107
Processus légers (threads)
61/107
Processus légers (threads)
62/107
Processus légers (threads)
63/107
Processus légers (threads)
64/107
Processus légers (threads)
65/107
Processus légers (threads)
66/107
Processus légers (threads)
67/107
Processus légers (threads)
68/107
Processus légers (threads)
Espace mémoire
Augmentation de l’espace mémoire pour chaque processus
Table des processus : information nécessaire pour la gestion de
l’espace mémoire d’un processus
Contenu : champs qui pointent sur des structures définissant des
régions mémoires
Utilisation dans un système avec mémoire virtuelle pour modifier les
tables des pages lors d’un changement de processus
Chaque thread dispose de sa propre pile (stack) d’exécution
dans l’espace mémoire du processus accessible par tous les threads
Pile d’un thread :
valeur d’un registre du processeur,
pointeur de pile (Stack Pointer, SP)
Transfert d’un thread à un autre : modification des valeurs des
registres
69/107
Processus légers (threads)
Espace mémoire
Sous Unix,
Un processus dispose également d’une pile système utilisée
lors de l’exécution de fonctions du noyau
Chaque thread doit donc disposer également d’une pile
système
Pile système :
Référence à des espaces mémoire du système, accessible
seulement par le système
Contenue dans les structures décrivant les threads, elles aussi,
dans l’espace système
70/107
Processus légers (threads)
71/107
Processus légers (threads)
72/107
Processus légers (threads)
Threads utilisateur
Mise en œuvre des processus multi-thread sans modification du système
d’exploitation
Simulation de l’exécution de plusieurs processus concurrents à
l’intérieur de notre programme.
Ajout des fonctions et des structures permettant la commutation
entre les autres parties du programme,
dans les processus usager pour supporter le multi-thread
Fonctions de sauvegarde les valeurs des registres du processeur et de
remplacement par de nouvelles valeurs
Transfert d’une partie de code d’un thread à un autre
Assignation de différentes piles à différents threads
Appels au système pour obtenir de nouveaux espaces mémoire
Maintenance de différentes structures de données pour connaı̂tre les
threads présents et contrôler leur exécution
Changement de thread dans un processus : appel une fonction du
module thread contenu dans le processus
73/107
Processus légers (threads)
Threads utilisateur
74/107
Processus légers (threads)
Threads utilisateur
Constat : Un thread peut retenir indûment le contrôle du CPU
pas appel aux fonctions de contrôle du module thread
Un thread qui s’exécute
contrôle le CPU
détermine quelle partie du code du processus sera exécutée en
suite
S’il n’appelle pas une fonction du module thread, il peut
conserver le contrôle aussi longtemps qu’il le désire
Solution : modification de tous les appels au système (les APIs)
pour inclure un appel au module thread à l’intérieur de chaque API
permet d’augmenter les occasions d’appeler le module thread
à chaque appel système, le module thread aura l’occasion de
reprendre le contrôle
forcer le transfert d’un thread à un autre
75/107
Processus légers (threads)
Threads utilisateur
76/107
Processus légers (threads)
Threads utilisateur
77/107
Processus légers (threads)
Threads noyau
78/107
Processus légers (threads)
Threads noyau
79/107
Processus légers (threads)
#include <pthread.h>
pthread create ()
pthread exit ()
pthread join ()
pthread attr *
Lors de la compilation : utilisation de l’option -pthread
80/107
Processus légers (threads)
Création de thread
#i n c l u d e <p t h r e a d . h>
i n t p t h r e a d c r e a t e ( pthread t * thread ,
pthread attr t * attr ,
void * (* s t a r t r o u t i n e ) ( void *) ,
void * arg ) ;
81/107
Processus légers (threads)
Terminaison et Attente
void p t h r e a d e x i t ( void * r e t v a l ) ;
i n t p t h r e a d j o i n ( p t h r e a d t th , v o i d ** t h r e a d r e t u r n ) ;
82/107
Processus légers (threads)
Remarques et bilan
83/107
Processus légers (threads) - Sémaphore et thread
84/107
Processus légers (threads) - Sémaphore et thread
85/107
Processus légers (threads) - Sémaphore et thread
Verrouillage/Déverrouillage
Verrouillage d’un sémaphore mutex
p t h r e a d m u t e x l o c k ( p t h r e a d m u t e x t * mutex )
Fonctionnement :
mutex libre : verrouillage immédiat et attribution au thread
appelant
mutex déjà verrouillé par un autre thread :
blocage du thread sur la fonction jusqu’à la libération du
mutex
verrouillage et attribution au thread (mise en concurrence des
threads précédemment bloqués)
Déverrouillage d’un sémaphore mutex
p t h r e a d m u t e x u n l o c k ( p t h r e a d m u t e x t * mutex )
86/107
Moniteurs et variables conditionnelles
Mécanisme de sémaphore
Programmation de la plupart des cas de synchronisation
Mais : les primitives P et V sont non structurées :
Il est facile d’effectuer des erreurs en les utilisant
Exécution d’une section critique doit
commencer par un appel à une primitive P
se terminer par un appel à une primitive V sur le même
sémaphore
sinon il est possible de rencontrer les situations suivantes :
exclusion mutuelle non assurée
interblocage
→ Conséquence importante sur les applications réelles
87/107
Moniteurs et variables conditionnelles
88/107
Moniteurs et variables conditionnelles
89/107
Moniteurs et variables conditionnelles
90/107
Moniteurs et variables conditionnelles
Moniteurs
Introduction
91/107
Moniteurs et variables conditionnelles
Moniteurs
Présentation
Moniteur :
collection de variables permanentes désignées comme des
variables d’état
peut être vu comme un module
variables d’état : mémorisation de l’état de la ressource
exportation de fonctions
réalisant les opérations possibles sur la ressource
ou mettent en œuvre les protocoles d’accès à la ressource
code d’initialisation des variables d’état :
inclus dans le moniteur
exécuté qu’un seule fois, avant toute fonction du moniteur
92/107
Moniteurs et variables conditionnelles
Moniteurs
Présentation
Variables permanentes
Accès uniquement depuis le moniteur
Conservation des valeurs entre les différents appels de
fonctions des moniteurs
Fonctions des moniteurs
peuvent comporter des variables locales et les paramètres
peuvent être visibles que dans l’environnement du moniteur
Exemple :
Exécution d’une fonction OP J exportée du module M :
M.OP J(Arg)
Exécution : semblable à un appel de fonction, mais assurance
de l’exlusion mutuelle
93/107
Moniteurs et variables conditionnelles
var
/* d e c l a r a t i o n d e s v a r i a b l e s p e r m a n e n t e s */
p r o c e d u r e OP 1 ( p a r a m e t r e s )
var
/* d e c l a r a t i o n d e s v a r i a b l e s l o c a l e s a OP 1 * /
begin
/ * Code de OP 1 * /
end / * OP 1 * /
p r o c e d u r e OP 2 ( p a r a m e t r e s )
var
begin
end
c o d e /* M */
/ * i n i t i a l i s a t i o n du m o n i t e u r * /
end monitor
94/107
Moniteurs et variables conditionnelles
Exclusion mutuelle
95/107
Moniteurs et variables conditionnelles
Variables de condition
Conditions de synchronisation
Variable de condition
mise en attente passive des processus, dans le moniteur
déclaration uniquement dans un moniteur
Des opérations sont associées aux variables conditionnelles :
WAIT et SIGNAL
96/107
Moniteurs et variables conditionnelles
97/107
Moniteurs et variables conditionnelles
Exemple
Code du moniteur
monitor Ressource ;
/* l i s t e d e s f o n c t i o n s e x p o r t e e s */
var
OCCUPEE : b o o l e a n
Libre : condition
p r o c e d u r e RESERVATION
begin
i f OCCUPEE t h e n Code du programme
L i b r e . WAIT
endif while (1) {
OCCUPEE = TRUE R e s s o u r c e . RESERVATION
end / * RESERVATION * / /* A c c e s a l a r e s s o u r c e */
R e s s o u r c e . LIBERATION
p r o c e d u r e LIBERATION }
begin
OCCUPEE = FALSE
L i b r e . SIGNAL
end / * LIBERATION * /
code
OCCUPEE = FALSE
end monitor
98/107
Moniteurs et variables conditionnelles
Problème du producteur/consommateur
99/107
Moniteurs et variables conditionnelles
100/107
Moniteurs et variables conditionnelles
Déclaration et initialisation
#i n c l u d e <p t h r e a d . h>
p t h r e a d c o n d t cond = PTHREAD COND INITIALIZER ;
101/107
Moniteurs et variables conditionnelles
Déclaration et initialisation
102/107
Moniteurs et variables conditionnelles
Utilisation
Remarques :
l’attente est toujours associée à un mutex
le mutex est libéré au moment de la mise en attente
103/107
Moniteurs et variables conditionnelles
Utilisation
i n t p t h r e a d c o n d b r o a d c a s t ( p t h r e a d c o n d t * cond ) ;
Remarques :
Un ou tous les threads en attente sur la condition sont réveillés
Les threads sont à nouveau en compétition pour le mutex
104/107
Moniteurs et variables conditionnelles
Exemple d’utilisation
#i n c l u d e <p t h r e a d . h>
struct {
enum {EMPTY, FULL} e t a t ;
int value ;
} tampon ;
v o i d * p r o d u c t e u r ( c h a r * msg ) {
while (1) {
p t h r e a d m u t e x l o c k (&mutex ) ;
w h i l e ( tampon . e t a t == FULL ) {
p t h r e a d c o n d w a i t (& wake up , &mutex ) ;
}
tampon . e t a t = FULL ;
tampon . v a l u e ++;
p t h r e a d c o n d s i g n a l (& wake up ) ;
p t h r e a d m u t e x u n l o c k (&mutex ) ;
}
}
105/107
Moniteurs et variables conditionnelles
Exemple d’utilisation
v o i d * consommateur ( v o i d ) {
while (1) {
p t h r e a d m u t e x l o c k (&mutex ) ;
w h i l e ( tampon . e t a t == EMPTY) {
p t h r e a d c o n d w a i t (& wake up , &mutex ) ;
}
p r i n t f ( ”%d\n” , tampon . v a l u e ) ;
tampon . e t a t = EMPTY
p t h r e a d c o n d s i g n a l (& wake up ) ;
p t h r e a d m u t e x u n l o c k (&mutex ) ;
}
}
}
106/107
Moniteurs et variables conditionnelles
To be continued...
107/107