0% ont trouvé ce document utile (0 vote)
27 vues107 pages

CoursSE 4

cours SE

Transféré par

kernoulilia
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
27 vues107 pages

CoursSE 4

cours SE

Transféré par

kernoulilia
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Système d’exploitation

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

1 Exclusion mutuelle et section critique

2 Processus légers (threads)


Sémaphore et thread

3 Moniteurs et variables conditionnelles

2/107
Exclusion mutuelle et section critique

Exclusion mutuelle et section critique


Introduction

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

Exemple : Problème du banquier

Soit une application bancaire très simple comportant deux


opérations :
créditer un compte : credit(C,S) : C=C+S ;
débiter un compte : debit(C,S) : C=C-S ;
Après compilation, ces deux opérations peuvent être traduites par
les instructions suivantes :
C=C+S C=C-S
ld R,c (a1 ) ld R,c (a2 )
add R,S,R (b1 ) sub R,S,R (b2 )
st R,c (c1 ) st R,c (c2 )

4/107
Exclusion mutuelle et section critique

Exemple : Problème du banquier


P1 : C=C+S P2 : C=C-S
ld R,c (a1 ) ld R,c (a2 )
add R,S,R (b1 ) sub R,S,R (b2 )
st R,c (c1 ) st R,c (c2 )

Soit la valeur initiale de C=C0


On a les les exécutions suivantes :
begin P1 , P2 end ;
a1 b1 c1 a2 b2 c2
C0 C0 + S1 C0 + S1 − S2
begin P2 , P1 end ;
a2 b2 c2 a1 b1 c1
C0 C0 − S2 C0 − S2 + S1
parbegin P1 , P2 parend ;
a1 a2 b1 b2 c1 c2
C0 C0 + S1 C0 − S2

5/107
Exclusion mutuelle et section critique

Exemple : Problème du banquier

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

Les solutions logicielles

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

Deux (ou plus) processus exécutent une


boucle (infinie) avec un segment de code,
i.e. la section critique (SC)
Objectif : à contrôler l’accès à la section 1 while (1) {
critique SR
accès par un seul processus à la fois 3 SE
SC
Pour cela, on va encadrer ce segment par
5 SS
une section d’entrée (SE) SR
une section de sortie (SS)
7 }
qui protègent la section critique
section restante (SR) : reste du code du
processus

8/107
Exclusion mutuelle et section critique

Solution : Essai 1

Partage en lecture, de deux variables in_1 et in_2, initialisées à 0

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

Ce programme n’assure pas l’exclusion mutuelle


d’exécution des deux sections critiques
Soit la chronologie suivante :
P1 et P2 sont en section restante (in_1 = in_2 = 0)
P1 teste while(in_2), et peut passer à la ligne suivante
COMMUTATION :
P2 rentre à son tour en section d’entrée, teste while(in_1)
et passe à la suite
il met in_2 à 1 et entre en SC
P1 reprend à in_1 = 1 et rentre en SC

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

Partage en lecture et en écriture, d’une variables tour, initialisée


(par exemple) à 1

Programme principal : tour = 1 ; parbegin P1 | P2 parend ;

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

Ce programme assure l’exclusion mutuelle


si les deux processus étaient en section critique en même
temps,
tour vaudrait à la fois 1 et 2
Mais un problème grave apparaı̂t :
si P2 , par exemple, reste endormi sur sa section restante,
P1 ne peut entrer une deuxième fois en section critique,
puisqu’il attend son tour (tour reste à 2) ;
→ le système ne fonctionne qu’en alternance parfaite.
Et que dire si l’un des processus est détruit ?

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

Reprise de l’idée de l’essai 1, mais inversion l’ordre des opérations


pour éviter le temps de latence entre le test et la protection
de la SC
Partage en lecture, deux variables in_1 et in_2, initialisées à 0

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

On peut encore définir une autre condition de bon fonctionnement


des sections critiques.
Propriété
Condition d’attente bornée : le nombre de processus qui entrent
en section critique entre le moment où P commence sa section
d’entrée et celui où il accède à sa SC est borné par une fonction du
nombre de processus déjà en attente de SC quand P entame sa
section d’entrée.

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

si P1 commence sa SE, P1 exécute d’abord in1 = 1


après cette instruction, P2 ne peut plus entrer en SC2 que si
tour == 2,
sinon il boucle dans while (in_2 && tour == 2) avec in_1== 1.
Si P2 entre ainsi en SC2 (peut-être impossible, mais on ne cherche
qu’une majoration),
quand P2 sort de SC2 , s’il essaie d’entrer à nouveau en section
critique, il remet in_2 à 1, puis tour à 1 et teste
(in_1 && tour == 1).
Quand P1 exécute tour = 2, cela peut permettre à P2 d’entrer une
seconde fois en SC2 .
Si P2 essaye ensuite une troisième fois d’entrer en SC2 ,
les deux conditions in1 et tour == 1 sont vraies,
et ceci ne peut être changé tant que P1 n’est pas entré en SC1 .
→ P1 n’attend donc pas plus de deux processus.

23/107
Exclusion mutuelle et section critique

Solution de Peterson
Remarques

Pour éviter toute attente infinie, on fait l’hypothèse que


la durée de l’exécution de la section critique de chaque
processus soit bornée
En particulier, assassinat et suicide sont exclus . . .

24/107
Exclusion mutuelle et section critique

Les solutions matérielles

Masquage d’interruption
Test And Set
Swap

25/107
Exclusion mutuelle et section critique

Les solutions matérielles


Masquage d’interruption

En environnement monoprocesseur : jouer sur le masquage


des interruptions
Technique de base utilisée par Unix

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

Les solutions matérielles


Test And Set

Instruction spéciale du processeur


utilisation un registre x et un mot a en mémoire
réalisation de ”x = a ; a = 1 ;” en une seule instruction.
TAS permet de lire et poser un verrou en prenant pour a
l’adresse de verrou
Pseudo-code :
1 i n t TAS( v e r r o u ) i n t * v e r r o u ;
{
3 int lu ;
lu = * verrou ; /* c o u p l e i n d i v i s i b l e */
5 * v e r r o u ˜:= 1 ; /* d ’ i n s t r u c t i o n s */
return ( lu ) ;
7 }

27/107
Exclusion mutuelle et section critique

Les solutions matérielles


Test And Set

Pour protéger une section critique, l’utilisation de test and set


donne le programme :
1 while (1) {
<SR>
3 do {
l u = TAS( v e r r o u ) ;
5 } while ( lu ) ;
<SC>
7 * verrou = 0 ;
}

28/107
Exclusion mutuelle et section critique

Les solutions matérielles


Swap

Instruction machine indivisible swap :


”x = 1 ; swap (x,a) ;” avec le même effet que TAS

29/107
Exclusion mutuelle et section critique

Les solutions matérielles


Problèmes

Solutions au problème de la gestion de l’exclusion mutuelle en


attente active
consommation de temps-machine (temps de fonctionnement
du processeur) pour simplement constater qu’il faut attendre
Solution : définir la notion de processus en sommeil sur un
événement
En attente passive d’un événement :
le processus ne concourt pas pour obtenir l’UC jusqu’à ce que
l’événement attendu se produise
chaque événement déclenche le réveil d’un ou plusieurs
processus en attente de cet événement

30/107
Exclusion mutuelle et section critique

Les solutions matérielles


attente passive avec TAS

Réalisation d’une attente passive avec TAS


while (1) {
2 <SR>
l u = TAS ( v e r r o u ) ;
4 i f ( lu ) {
<m e t t r e P en a t t e n t e >
6 }
<SC>
8 * verrou = 0 ;
< r e v e i l l e r ( au moins ) un p r o c e s s u s en a t t e n t e >
10 }

31/107
Exclusion mutuelle et section critique

Les solutions matérielles

Attente passive avec TAS : pas une solution universelle


Soit l’exécution suivante (en partant avec verrou == 0) :
P1 P2
lu1 = TAS(verrou) ;
if (lu1 ) . . ./* faux */
lu2 = TAS(verrou) ; /* lu2 == 1 */
< SC1 >
verrou = 0 ;
< réveiller P2 >
if (lu2 ) < mettre P2 en attente >
et P2 est en attente d’un événement qui s’est déjà produit . . .
→ C’est la notion de sémaphore qui permettra de garder une
trace du nombre d’événements.

32/107
Exclusion mutuelle et section critique

Synchronisation, coordination
Les sémaphores - Origine (Dijkstra)

Objet abstrait clarifiant l’écriture de protection de SC

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)

P(S) : if (S ≤ 0) P(S) ; else S– ;


V(S) : S++
Autrement dit :
S représente le nombre de ”places” disponibles
l’entrée et la sortie du sémaphore sont supposés corrects
le nombre de places est limité par la valeur initiale (ou par le
nombre d’appels à V())
lors d’une demande de places, si S vaut 0 alors il y a attente

34/107
Exclusion mutuelle et section critique

Emploi du sémaphore

Illustration des possibilités des sémaphores


Protection d’une section critique accessible à n processus
Rendez-vous
Séquentialisation de deux tâches

35/107
Exclusion mutuelle et section critique

Protection d’une section critique accessible à n processus

Un sémaphore sectionCritique, initialisé à 1.


semaphore sectionCritique = 1 ;
parbegin P1 | P2 | ... | Pn parend ;
Code de Pi :
while (1) {
2 <SRi>
P( s e c t i o n C r i t i q u e ) ;
4 <SCi>
V( s e c t i o n C r i t i q u e ) ;
6 }

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

Séquentialisation de deux tâches

Pi exécute la tâche Si avec i = {0, 1}


On veut que S1 ne soit exécuté qu’après la fin de S0
On crée un sémaphore S, initialisé à 0.
semaphore S = 0
P0 P1
... ...
S0 P(S)
V( S) ; S1
... ...

38/107
Exclusion mutuelle et section critique

Limites

Principal désavantage : attente active (gaspillage de CPU)


Solution : implémentation de sémaphore sous forme d’appels
systèmes
1 le processus en attente est endormi
2 Le système d’exploitation le réveille quand le processus peut
continuer

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)

Problématique : Contrôle du flux entre le(s) producteur(s) et


le(s) consommateur(s) par un tampon
On dispose d’un tampon de taille bornée dans lequel les
producteurs écrivent, et les consommateurs lisent
Objectif : maximiser la parallélisation entre les producteurs et
consommateurs malgré leur différence d’exécution.
La taille est d’autant plus grande que la différence de vitesse
d’exécution est grande.

41/107
Exclusion mutuelle et section critique

Fonctionnement

Fonctionnement basé sur deux conditions de blocage :


Condition de blocage des producteurs : le tampon est plein
Pas de possibilité d’y déposer des informations sans écraser
l’information non consommé
Condition de blocage des consommateurs : le tampon est vide
Remarque : Le fonctionnement est symétrique : Le
consommateur est producteur de case vide.
Applications :
les entrées/sorties tamponnées (gestion de spool)
le traitement en pipeline (tubes UNIX)

42/107
Exclusion mutuelle et section critique

Producteur(s)/Consommateur(s)
Solution

Utilisation de deux sémaphores :


placeDispo, initialisé à la taille du tampon
infoPrete, initialisé à 0.
semaphore placeDispo = N
semaphore infoPrete = 0
Code du producteur Code du consommateur
while (1) { while (1) {
2 calculer ( info ); 2 P( i n f o P r e t e ) ;
P( p l a c e D i s p o ) ; extraire ( info );
4 deposer ( info ) ; 4 V( p l a c e D i s p o ) ;
V( i n f o P r e t e ) ; u t i l i s e r ( info );
6 } 6 }

43/107
Exclusion mutuelle et section critique

Lecteur(s)/Rédacteur(s)

Problématique : gestion d’un accès exclusif suivant la


catégorie d’utilisateurs
Objectif :
Plusieurs lecteurs peuvent accèder de manière simultanée à
une zone,
alors qu’un rédacteur a un accès exclusif, également exclusif de
tout lecteur, à cette zone.
Applications : accès aux fichiers sur disque, ou aux zones
mémoire

44/107
Exclusion mutuelle et section critique

Lecteur(s)/Rédacteur(s)
Solution 1

Première solution : utilisation de deux sémaphores


lecteur, initialisé à 1
rédacteur initialisé à 1
une variable partagée Nblect, initialisée à 0

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

Inconvénient : possibilité de famine pour les rédacteurs


→ Cette première solution donne la priorité au lecteur

47/107
Exclusion mutuelle et section critique

Lecteur(s)/Rédacteur(s)
Solution 2

Seconde solution : utilisation de trois sémaphores :


lecteur, initialisé à 1
rédacteur initialisé à 1
fifo, initialisée à 1
une variable partagée Nblect, initialisée à 0
→ Dans cette solution, la priorité est donnée aux rédacteurs

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;

Code du lecteur Code du rédacteur


1 while (1) { 1 while (1) {
P( f i f o ) ; P( f i f o ) ;
3 P( l e c t e u r ) ; 3 P( r e d a c t e u r ) ;
Nblect = Nblect + 1; V( f i f o )
5 i f N b l e c t == 1 t h e n 5 LectureEtEcriture ();
P( r e d a c t e u r ) V( r e d a c t e u r ) ;
7 V( l e c t e u r ) ; 7 }
V( f i f o ) ;
9 Lectures ();
P( l e c t e u r ) ;
11 Nblect = Nblect − 1;
i f N b l e c t == 1 t h e n
13 V( r e d a c t e u r )
V( l e c t e u r ) ;
15 }

49/107
Exclusion mutuelle et section critique

Le problème des philosophes

Dı̂ner des philosophes : problème classique de synchronisation de


processus
Les données initiales sont les suivantes :
5 philosophes (les processus) autour d’une table
un plat de riz pour chaque philosophe (ou un seul pour tous
les philosophes)
Chaque philosophe dispose d’une assiette et d’une baguette
(l’une des ressources partagées) à sa droite. A sa gauche, se
situe donc la baguette de son voisin

50/107
Exclusion mutuelle et section critique

Le problème des philosophes


Illustration

source : http://www.iro.umontreal.ca/~pift1025/H08/

51/107
Exclusion mutuelle et section critique

Le problème des philosophes


Règles

Les philosophes sont dans trois états possibles :


Penser (pendant un temps indéterminé)
Etre Affamé (pendant un temps déterminé et fini – sinon il y
a risque de famine)
Manger (pendant un temps déterminé et fini)

52/107
Exclusion mutuelle et section critique

Le problème des philosophes


Contraintes

Les contraintes sont les suivantes :


si un philosophe a faim, il passe dans l’état affamé et attend
que les baguettes soient disponibles
pour manger, un philosophe a besoin de deux baguettes (à
droite de son assiette, et à droite de celle de son voisin)
si un philosophe n’arrive pas à s’emparer de deux baguettes, il
reste affamé pendant un temps déterminé, puis tente à
nouveau de manger

53/107
Exclusion mutuelle et section critique

Le problème des philosophes


Objectif

La solution doit permettre à chaque philosophe de manger


Objectif : trouver un ordonnancement des philosophes afin
que tous puissent manger

54/107
Exclusion mutuelle et section critique

Le problème des philosophes


Représentation de chaque philosophe

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]
}

Objectif : remplacer la partie prendre baguette et


rendre baguette par des appels aux primitives P et V

55/107
Exclusion mutuelle et section critique

Le problème des philosophes


Solutions
Solution utilisant les sémaphores :
semaphore sem_baguette[5] = {1,1,1,1,1} ;
Code du Philosophei
while (1) {
2 penser ()
P( b a g u e t t e [ i ])
4 P( b a g u e t t e [ ( i +1)%5])
manger ( )
6 V( b a g u e t t e [ i ])
V( b a g u e t t e [ ( i +1)%5])
8 }

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

Le problème des philosophes


Solutions
Solution 1
On veut s’assurer qu’au plus quatre philosophes sont assis à table.
On utilise un sémaphore qui comptabilise les philosophes à table.
semaphore sem_baguette[5] = {1,1,1,1,1} ;
semaphore Table = 4 ;
Code du Philosophei
while (1) {
2 penser ()
P( T a b l e ) ;
4 P( b a g u e t t e [ i ])
P( b a g u e t t e [ ( i +1)%5])
6 manger ( )
V( b a g u e t t e [ i ])
8 V( b a g u e t t e [ ( i +1)%5])
V( T a b l e ) ;
10 }

57/107
Exclusion mutuelle et section critique

Le problème des philosophes


Solutions
Solution 2 On casse la symétrie du problème :
les philosophes de numéro pair prennent leur baguette droite d’abord
les philosophes de numéro impairs prennent leur baguette gauche d’abord
semaphore sem_baguette[5] = {1,1,1,1,1} ;
Code du Philosophei
while (1) {
2 penser ()
i f ( i %2) {
4 P( b a g u e t t e [ i ] )
P( b a g u e t t e [ ( i +1)%5])
6 } else {
P( b a g u e t t e [ ( i +1)%5])
8 P( b a g u e t t e [ i ] )
}
10 manger ( )
V( b a g u e t t e [ i ] )
12 V( b a g u e t t e [ ( i +1)%5])
}

58/107
Exclusion mutuelle et section critique

Le problème des philosophes


Remarques

Problème plus complexe qu’il n’y paraı̂t :


Base des problèmes de synchronisation, liés aux systèmes
distribués
Cas de figure particuliers lors de l’implémentation de
l’algorithme :
Mort d’un philosophe : Que se passe-t-il s’il meurt avec ses
baguettes en main ?
Conservation de ressources pendant un temps infini ?
Coalition de philosophes : un philosophe ne peut obtenir ses
fourchettes car les autres philosophes sont ligués contre lui

59/107
Exclusion mutuelle et section critique

To be continued...

60/107
Processus légers (threads)

Processus légers (threads)

Objectif : atténuer les problèmes liés aux processus lourds


Définition d’un mécanisme permettant d’avoir plusieurs files
d’exécution (ou threads) dans un même espace de ressources
non dupliqué
Partage de ressources communes
utilisation du même espace mémoire
Tous les threads peuvent accéder aux mêmes variables ou
structures globales
accès et exécution du même code
Certains threads peuvent n’exécuter qu’une partie du code
tandis que d’autres threads exécutent les autres parties du code

61/107
Processus légers (threads)

Processus légers (threads)

Threads : correspondent à différents points d’exécution dans


le programme
Chaque thread doit donc avoir un contexte d’exécution
différent
Contexte d’exécution : champs de la table de processus
associés au contrôle du CPU :
la valeur des registres du processeur
l’état et la priorité du thread

62/107
Processus légers (threads)

Ressources associées aux threads


Deux types de ressources :
Ressources du processus partagées par tous les threads
Mappage mémoire et fichiers ouverts
Ressources communes définies au niveau du processus et
appartenant au processus
Utilisation possible par tous les threads
Ressources spécifiques à chaque thread
Définition du contexte d’exécution de chaque thread
Valeur des registres du processeur
État de la pile
Pile (stack) : élément important du contexte d’exécution d’un
processus ou thread
Contient les variables locales aux fonctions
Contrôle la navigation dans les appels imbriqués de fonctions

63/107
Processus légers (threads)

Processus et programmation concurrente

Processus traditionnel : processus avec un seul thread


beaucoup mieux isolés et protégés les uns des autres
espace mémoire distinct et protégé
Programmation concurrente :
Nécessite de briser l’isolation entre les processus
Par exemple : utilisation d’une zone de mémoire commune

64/107
Processus légers (threads)

Processus et programmation concurrente


Processus multi-thread : correspond à plusieurs processus
traditionnels mais
Possibilité pour plusieurs threads de partager le même espace
mémoire
Attention : conflits potentiels entre les threads et introduction
de nouveaux besoins de synchronisation
Exemple : Modification de la même variable globale en même
temps, par deux threads
Nécessité d’un compromis entre le partage de ressources et les
besoins de synchronisation
Aspect multi-thread : plus de possibilités pour les concepteurs
d’application
Plus facile d’écrire une application utilisant plusieurs threads dans
un même programme que d’écrire plusieurs programmes (un par
processus)

65/107
Processus légers (threads)

Mise en œuvre des threads

Mise en œuvre des processus multi-thread


Modification
soit au niveau du système (noyau)
soit au niveau du code exécutable de l’utilisateur
Exécution de plusieurs threads à l’intérieur d’un processus
utilisateur
Structures de données et de fonctions au niveau système pour
implanter et gérer les processus
Modification des structures et des fonctions pour supporter le
multi-thread

66/107
Processus légers (threads)

Mise en œuvre des threads

Noyau : contient de nouvelles structures de données décrivant


les threads
Suppression de certains champs de la table des processus pour
les placer dans la structure décrivant un thread
En particulier, les champs associés au contrôle du CPU :
la valeur des registres du processeur
l’état et la priorité du thread

67/107
Processus légers (threads)

Mise en œuvre des threads

Chaque thread : contient une référence au processus hôte


Réduction de l’information contenue dans la table des
processus
Remplacement des champs associés au CPU par des
références sur les threads qui compose le processus,
i.e., des pointeurs sur les structures décrivant les 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)

Algorithme d’allocation CPU

Processus légers : threads supportés au niveau du système


Modification de l’algorithme d’allocation du CPU pour
connaı̂tre les threads ”prêt à exécuter”
Passage au niveau des threads : choisir le prochain thread (et
non plus le prochain processus) parmi ceux ”prêt à exécuter”
Problème d’une meilleure répartition du temps CPU entre les
processus :
Il faut éviter que plus un processus a de threads, plus il
obtiendra une partie importante du temps CPU

71/107
Processus légers (threads)

Système SMP (Symmetric Multi Processor )


Processus légers : particulièrement utiles dans un système
avec plusieurs processeurs
On parle de système SMP (Symmetric Multi Processor ) avec
mémoire commune ou partagée
”Symétrique” : tous les processeurs ont un rôle similaire
Pas un processeur maı̂tre qui contrôle le travail des autres
Distribution des threads sur les différents processeurs
Exécution en parallèle de plusieurs threads (absolument en
même temps)
Si nécessaire, assignation de tous les processeurs aux différents
threads d’un même processus
exécution très rapide du processus
Exécution des threads d’un même processus en parallèle sur
plusieurs processeurs : support des threads par le système
(noyau)

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

Quand effectuer un changement de thread ?


de manière synchrone, c’est-à-dire, quand le thread qui
s’exécute en fait la demande
système concurrent coopératif :
comportement coopératif des threads
appel régulier au fonction du module thread pour assurer un
partage équitable du temps CPU

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

Dans un système multi-thread préemptif


Prise de contrôle de manière asynchrone par le module thread,
c’est-à-dire lors des interruptions
Minimum de participation du système (noyau)
Redonner le contrôle au module thread après le traitement
d’une interruption

76/107
Processus légers (threads)

Threads utilisateur

Dans un système de thread utilisateur


Allocation du CPU par le système sur une base de processus
A l’intérieur du processus le module thread
distribue le temps CPU obtenu entre les différents threads
applique son propre algorithme d’allocation qui partage le
temps du processus entre les threads du processus

77/107
Processus légers (threads)

Threads noyau

Processus légers et les threads utilisateur : à l’intérieur d’un


processus utilisateur
Organisation du code du noyau d’un système d’exploitation
Le noyau crée
l’image ou le concept de processus et gère lui-même
l’exécution de son code.
utilise le concept de thread pour l’aider à gérer l’exécution de
son code
→ Thread noyau qui exécute du code du noyau
Threads noyau
supportés que par des fonctions et des structures de données à
l’intérieur du noyau
dans une couche inférieur du noyau

78/107
Processus légers (threads)

Threads noyau

Approche micronoyau (micro kernel)


parties supérieures du noyau : processus/threads qui
s’exécutent de manière indépendante
partie inférieure : le micro-noyau, assure la synchronisation et
le transfert du CPU entre ces processus/threads

79/107
Processus légers (threads)

Utilisation des Threads : l’API POSIX

#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 ) ;

Création d’un nouveau processus léger


avec les attributs indiqués par la structure pointée par attr
(NULL = attributs par défaut).
Exécution de la fonction start routine, avec les arguments
dans le pointeur arg en paramètre
Valeur de retour : identifiant du processus léger

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 ) ;

Terminaison due processus léger (avec code de retour)


lorsque la fonction qui lui est associée se termine par return
val retour,
lorsque le processus léger exécute un
pthread exit ( val retour ).

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 ) ;

Attente de la fin d’un processus léger, par le processus père


Récupération éventuellement son code de retour

82/107
Processus légers (threads)

Remarques et bilan

Modifications du fonctionnement des processus légers


priorités
algorithme d’ordonnancement, etc.
en manipulant les attributs sont associés (fonction
pthread attr *)
Threads POSIX :
API
utilisation standardisée indépendante de l’implémentation
retenue sur le système d’exploitation utilisé

83/107
Processus légers (threads) - Sémaphore et thread

Sémaphore dans les Threads (mutex)

Sémaphore dans la librairie pthread : mutex


Sémaphore booléen
Définition d’une variable globale de type pthread mutex t

84/107
Processus légers (threads) - Sémaphore et thread

Sémaphore dans les Threads (mutex)


Création/initialisation
Initialisation statique avec la constante
PTHREAD MUTEX INITIALIZER :
p t h r e a d m u t e x t mutex = PTHREAD MUTEX INITIALIZER ;

Initialisation dynamique (avec vérification des erreurs possibles)


p t h r e a d m u t e x i n i t ( p t h r e a d m u t e x t * mutex ,
const pthread mutexattr t * a t t r i b u t s )

si attributs est à NULL, les paramètres par défaut sont


utilisés
Destruction d’un sémaphore :
p t h r e a d m u t e x d e s t r o y ( p t h r e a d m u t e x t * mutex )

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

Moniteurs et variables conditionnelles


Introduction

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

Moniteurs et variables conditionnelles


Introduction

Problème avec les sémaphores :


1 Possibilité d’oublier d’inclure dans les sections critiques, toutes
les instructions utilisant les objets partagés
2 Difficulté à identifier la finalité d’une primitive P ou V sans
connaı̂tre les autres opérations effectuées sur le sémaphore
Solution partielle : définition et utilisation de sections critiques
conditionnelles

88/107
Moniteurs et variables conditionnelles

Sections critiques conditionnelles (SCC)


Principes
Proposition de notation structurée permettant de spécifier la
synchronisation
Variables partagées explicitement définies dans des groupes
(les ressources)
Chaque variable
est au plus dans une ressource
ne peut être accèdée qu’à l’aide d’instructions contenues dans
la section critique conditionnelle
Garantie de l’exclusion mutuelle : pas d’entrelacement de
l’exécution des instructions d’une même région
Autorisation de conditions de synchronisation grâce à des
d’expressions booléenne explicites contenues dans la section
critique conditionnelle

89/107
Moniteurs et variables conditionnelles

Sections critiques conditionnelles


Remarques
Sections critiques conditionnelles : solutions à des nombreux problèmes
mais elles sont coûteuses à implémenter
Possibilité d’inclure des références à des variables locales dans les
conditions dans les instructions de la SCC
Chaque processus doit évaluer ses propres conditions
Multithreading : nombreux changements de contexte, potentiellement
inutiles (le processus réveillé peut avoir sa condition fausse)

Implémentation possible à peu de frais en utilisant un mécanisme


d’attente active, si chaque processus exécute sur son propre processeur et
sa propre mémoire partagée
Possibilité d’imbrication des sections critiques, si les ressources sont
distinctes.
NB : attention aux interblocages
SCC peu utilisées mais inspiration pour d’autres méthodes : moniteurs
(variables conditionnelles) et types protégés en ADA95

90/107
Moniteurs et variables conditionnelles

Moniteurs
Introduction

Plusieurs problèmes restent en suspend malgré les SCC :


Dispersion dans les processus, des instructions des SCC qui
exécutent des opération sur des variables (ou ressources)
Nécessite d’étudier tout le programme pour avoir une idée de
l’utilisation des ressources
Pas d’assurance de l’intégrité des structures de données
Aucun contrôle : aucune assurance que les opérations sur les
variables/ressources ne se font pas en dehors de la SC
Moniteurs : encapsulation de la description et des opérations
associées aux ressources dans la définition de la SC

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

Structure générale d’un moniteur


m o n i t o r M;
/* 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
/* 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

Exclusion mutuelle : solution au problème de compétition


entre processus
Mais les moniteurs ne permettent pas de gérer leur
coopération
Solution : introduction des variables conditionnelles dans les
moniteurs

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

Fonctionnement des moniteurs


Variable de condition : COND
COND.WAIT :
Mise en attente passive du processus, dans une file d’attente
associée à la variable COND
Abandon de l’exclusion mutuelle du moniteur (la contrainte
est en fait libérée)
COND.SIGNAL :
si aucun processus n’est bloqué sur COND, le processus
exécutant COND.SIGNAL continue
Il n’y a pas de mémorisation du signal
sinon, le processus exécutant COND.SIGNAL est suspendu
temporairement et le premier processus en attente est réactivé
Remarques :
un processus suspendu temporairement poursuit son exécution
s’il n’existe plus de processus en exécution dans le moniteur
Priorité aux processus ayant envoyés des signaux, par rapport
aux processus devant exécuter une fonction du moniteur

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

Utilisation d’un moniteur


Tampon : une seule place (une chaı̂ne de caractères)
Un seul producteur et un seul consommateur se partagent le tampon
m o n i t o r Tampon
var procedure E x t r a i r e () : string
Tampon : s t r i n g begin
P l e i n : boolean i f ( ! p l e i n ) then
Libre : condition l i b r e . WAIT
endif
procedure Deposer ( message : string ) m e s s a g e = Tampon
begin P l e i n = FALSE
i f P l e i n then L i b r e . SIGNAL
L i b r e . WAIT end / * E x t r a i r e * /
endif
Tampon = m e s s a g e code
P l e i n = True P l e i n = FALSE
L i b r e . SIGNAL end monitor
end / * D e p o s e r * /

99/107
Moniteurs et variables conditionnelles

Threads et variables de condition

Implémentation des moniteurs et des variables conditionnelles


dans les bibliothèques des threads

100/107
Moniteurs et variables conditionnelles

Déclaration et initialisation

Définition d’une variable de condition :

#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

Mise en place d’attributs


i n t p t h r e a d c o n d i n i t ( p t h r e a d c o n d t * cond ,
pthread condattr t * cond attr );

Initialisation de la variable cond avec


les attributs spécifiés par cond attr
ou les attributs par défaut si cond attr vaut NULL
Remarque :
Attributs : possibilité de partage des variables de condition
entre plusieurs processus lourds via la mémoire partagée

102/107
Moniteurs et variables conditionnelles

Utilisation

Attente de condition (WAIT)


i n t p t h r e a d c o n d w a i t ( p t h r e a d c o n d t * cond ,
p t h r e a d m u t e x t * mutex ) ;

cond : variable de condition


mutex : sémaphore associé

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

Signalisation de la condition (SIGNAL)


i n t p t h r e a d c o n d s i g n a l ( p t h r e a d c o n d t * cond ) ;

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 ;

p t h r e a d m u t e x t mutex = PTHREAD MUTEX INITIALIZER ;


p t h r e a d c o n d t wake up = PTHREAD COND INITIALIZER ;

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

Vous aimerez peut-être aussi