Vous êtes sur la page 1sur 23

REPUBLIQUE ALGERIENNE DEMOCRATIQUE ET POPULAIRE

Ministère de l’enseignement supérieur et de la recherche scientifique


Université de Jijel

Faculté des Sciences exactes et Informatique


Département d’informatique

« Parfois nous cherchons ce que nous ne sommes pas encore prêts à


trouver. Tout est question d’opportunité ou de synchronisation. »
Yves M
1. Introduction : Un système d'exploitation dispose de ressources (imprimantes, disques,
mémoire, fichiers, base de données, ...), que les processus peuvent vouloir partager. Une
ressource est soit locale, soit commune à plusieurs processus
Locale : utilisé par un seul processus.
Commune ou partageable par plusieurs processus.

Une ressource peut possède un ou plusieurs points d’accès à un moment donne :


Un seul : on parle de la ressource critique, Ex : une zone de mémoire
partagée en écriture entre plusieurs utilisateurs.
Plusieurs points d’accès : par exemple, un fichier en lecture utilisable par
plusieurs processus .
Ils sont alors en situation de concurrence (race) vis à vis des ressources et Le SE doit
contrôler l’utilisation de la ressource critique.
Les processus concurrents ont besoin de :
Partager des données (données métier par exemple)
Se synchroniser (pour ordonnancer les tâches par exemple)
Le résultat des processus concurrents est l’Incohérence ou non-disponibilité des ressources,
alors il faut synchroniser les processus.

 Définition de la synchronisation :
La synchronisation (sun, « ensemble » et khrónos, « temps ») est l'action de
coordonner plusieurs opérations entre elles en fonction du temps. On appelle
synchronisation la mise en œuvre des relations entre processus en vue de Respecter
les contraintes de coopération.

2. Exclusion mutuelle
Les processus disposent chacun d'un espace d'adressage protégé inaccessible aux autres
processus. Pour communiquer et s'échanger des données, les processus peuvent utiliser des
outils de communications offerts par le système. La manipulation de ces outils de
communication doit se faire dans le respect de règles de synchronisation qui vont assurer que
les données échangées entre les processus restent cohérentes et ne sont pas perdues. Un
premier problème de synchronisation est celui de l'accès par un ensemble de processus à une
ressource critique , c'est-à-dire une ressource à un seul point d'accès donc utilisable par un
seul processus à la fois.
 Définition de la ressource critique : Les ressources partagée, comme des zones
mémoire, cartes d'entrées/sorties, etc., sont dites critiques si elles ne peuvent être
utilisées simultanément que par un seul processus. On appelle ressource critique tout
objet : variable, table, chier, périphérique, ... qui peut faire l'objet d'un accès
concurrent (ou simultané) par plusieurs processus.
 Définition de la section critique : Une SC est une suite d'instructions qui opèrent sur
un ou plusieurs ressources partagées (critiques) et qui nécessitent une utilisation
exclusive de ces ressources. Les portions de code qui manipulent des ressources
critiques sont appelées des sections critiques. Ces sections doivent être exécutées en
exclusion mutuelle.

1
Les problèmes d'incohérences des résultats, posé par les accès concurrents, montrent que la
solution consiste à exécuter les sections critiques en exclusion mutuelle. C'est à dire qu'une
section critique (SC) ne peut être entamée (ou exécutée) que si aucune autre SC du même
ensemble n'est en exécution.

Le principe général d'une solution garantissant que l'exécution simultanée de plusieurs


processus ne conduirait pas à des résultats imprévisibles est : avant d'exécuter une SC, un
processus doit s'assurer qu'aucun autre processus n'est en train d'exécuter une SC du même
ensemble. Dans le cas contraire, il ne devra pas avancer tant que l'autre processus n'aura pas
termine sa SC.roblème !

 Comment assurer l’exclusion mutuelle ?

On ajoute un protocole avant et après chaque section critique .Ces protocoles assureront
l’exclusion mutuelle.

Pour réaliser l’exclusion mutuelle, il y a plusieurs propriétés à respecter:

à tout instant un processus au plus peut se trouver en section critique.


si plusieurs processus sont bloqués en attente de la ressource critique, l'un d'eux doit
pouvoir y entrer au bout d'un temps fini.
si un processus est bloqué hors d'une section critique, ce blocage ne doit pas empêcher
l'entrée d'un autre processus en sa section critique.
la solution doit être la même pour tous les processus.

Hypothèse 1: tout processus sort de section critique au bout d'un temps fini .

Hypothèse 2 : Les vitesses relatives des processus sont quelconques.

Hypothèse 3 : Les priorités ou les droits des processus sont quelconques.

 Protocole d’entrée/ sortie de la section critique :

1. protocole d’entrée en SC : ensemble d’instruction qui permet à un processus la


vérification et le non progression éventuelle.
2. protocole de sortie de SC : ensemble d’instruction qui permet à un processus ayant
terminé sa SC d’avertir d’autres processus en attente que la route est libre .

 la structure d’un processus


process Pi(i=1..n)
loop
... section non-critique ...
Protocole d’entrée
section critique (SC)
Protocole de sortie
endloop

2
3. Conditions nécessaires pour réaliser une exclusion mutuelle :

Une solution au problème de la section critique doit satisfaire aux 4 besoins suivants :

A. exclusion mutuelle : si le processus Pi exécute sa section critique , aucun autre


processus ne peut exécuter sa section critique .
B. déroulement : Un processus qui se trouve hors de sa SC ne doit pas empêcher un
autre processus d’entrer dans sa SC
C. Absence de blocage : Si plusieurs processus attendent pour entrer en SC, et si aucun
processus n’est déjà en SC, alors un des processus qui attend doit pouvoir entrer en
SC au bout d’un temps fini.
D. Attente limitée : il doit exister une limite au nombre de fois que l’on permet à d’autre
processus à entrer dans leurs sections critiques après qu’un processus à effectuer une
requête pour entrer dans sa section critique et avant que la requête ne soit accordée .
Remarque : Code identique (propriété souhaitable par souci de simplicité) :Le code qui
protège la section critique (protocole d’entrée et protocole de sortie) est le même pour toutes
les entités.

4. Classification des solutions :

Les différentes solutions apportées au problème de l’exclusion mutuelle que nous verrons
peuvent être classées selon l’attente des tâches pour la ressource et selon l’environnement sur
lequel ces tâches s’exécutent. 2 grandes classes de solutions envisageables :

A. Solutions d’attente active : on fait boucler le processus en attendant que la condition


soit réalisée . Solution Ad hoc, sans arbitrage, intégrée aux codes programmeur.

Protocole d’entrée en section critique

<section de code critique>

Protocole de sortie de section critique

B. Solutions d’attente passive : Allocation de ressource incorporant appel implicite à un


arbitre, on fait passer le processus dans un état dit bloqué.

Demande de la ressource

<section de code critique>

Libération de la ressource

3
5. Solutions d’attente active :

a) Solutions matérielles avec attente active : Il existe des solutions qui utilisent des
dispositifs matériels particuliers pour résoudre le problème de la section critique.
Ces solutions sont utilisées dans la pratique sur systèmes monoprocesseurs
centralisés.
Exclusions mutuelle par masquage des interruptions :
 Protocole d’entrée en SC : masquer les interruptions, La SC ne peut être
interrompue car les changements de contexte sont impossibles
 Protocole de sortie de SC : démasquer les interruptions
Processus P :

tant que (vrai)faire

masquer_les_IT; // entrée en section critique

section_critique;

démasquer_les_IT;// sortie de section critique

hors_section_critique;

fait;

Critiques de la solution :

 SC longue : perte d’interruptions


 dangereux un processus peut oublier de démasquer les IT
 inadaptée dans le cas multiprocesseur
Conclusion : Technique utile dans le noyau, mais pas au niveau utilisateur. Elle assure
l'exclusion mutuelle, si le système est monoprocesseur puisque le masquage des interruptions
concerne le processeur qui a demandé ce masquage. Les autres processus exécutés par un
autre processeur pourront donc accéder aux ressources partagées.

Exclusions mutuelle par instructions spéciales indivisibles :(Verrou et attente


active) En général, le problème de l’exclusion mutuelle se résoudre en utilisant
un verrou. Processus P

tant que (vrai)faire


acquérir verrou;
Section critique;
relâcher verrou;
hors SC;
fait;

4
 Réalisation d’un verrou : Un verrou est une variable booléenne partagée
-verrou=vrai la ressource critique n’est pas libre
-verrou=faux la ressource critique est libre
Le problème : acquisition atomique du verrou!
En général, il existe des instructions câblées telles que Swap qui échange de manière
atomique deux variables, Test and Set qui teste et modifie de manière atomique une variable.
 Réalisation d’un verrou avec swap atomique :
procédure swap (booléen x,y)

Booléen copie=x;x=y;y=copie;

Contexte commun :
Booléen verrou=faux; //variable partagée initialisée

Processus P
//entrée en section critique
Booléen macopie;
tant que (vrai) faire
macopie=vrai;
tant que (macopie) faire
swap(macopie,verrou);
fait;//attente active
section critique;
// sortie de section critique
verrou=faux;

 Inconvénient : - mauvaise utilisation du processeur c.-à-d. attente active


 L’instruction TestAndSet (lock) : Cette solution au problème de l’exclusion
mutuelle est basée sur un support matériel, à savoir une instruction spécifique du
langage machine .l’instruction (Test and set) charge le contenu d’un mot mémoire
dans un registre, puis met une valeur non-nulle à cet emplacement mémoire, ces deux
opérations étant garanties comme indivisibles. Pour assurer l’atomicité de cette
instruction, le processeur qui l’exécute verrouille le bus de données, pour empêcher les
autres processeurs d’accéder à la mémoire pendant la durée de l’opération.

Booléen TestAndSet(lock) Processus Pi :


{
If(lock) While (true) do { //Actions avant section
Return true ; critique
Else
While (TestAndSet(lock)) Donothing;
{Lock=true;
return false; SC
}
} Lock=false;

//actions après section critique}

5
Cette solution est valable et efficace, même dans le cas d’un système multiprocesseur, mais le
problème c’est l’attente active.

b) Solutions logicielles avec attente active :

Algorithme de Dekker : Dekker introduit la notion de candidature à l'entrée


en section critique : chaque processus annonce sa candidature à l'autre grâce à
une variable partagée (un tableau). Si plusieurs candidatures surviennent
simultanément, une priorité (variable) gère le conflit. La famine est évitée,
l'exclusion mutuelle est garantie, il n'y a pas d'inter blocage.

Algorithme :

//déclaration et initialisation des variables communes


booléen C[2]={faux,faux};//candidature
entier T=0;//priorité

Processus P0
tant que vrai faire
//entrée en SC
C[0]=vrai;
tant que (C[1])faire //P1 est en SC ou demande à
y entrer
tant que(T==1)faire C[0]=faux; //P1 est prioritaire
C[0]=vrai; //T=0
Section_critique;
//sortie de SC
C[0]=faux;
T=1;
Hors SC;
Fin

Processus P1
tant que vrai faire
//entrée en SC
C[1]=vrai;
tant que (C[0])faire //P1 est en SC ou demande à y
entrer
tant que(T==0) faire C[1]=faux; //P1 est prioritaire
C[1]=vrai; //T=1
Section_critique;
//sortie de SC
C[1]=faux;
T=0;
Hors SC;
Fin

6
Algorithme de Peterson : Peterson propose longtemps après Dekker une solution
plus simple d'exclusion mutuelle par attente active.

Algorithme

//déclaration et initialisation des variables communes


booléen C[2]={faux,faux};//candidature
entier T=0;//priorité

Processus P0
tant que (vrai)faire
//entrée en SC
C[0]=vrai;T=1;
tant que (C[1] and T==1); //attente en cas de conflit
Section_critique;
//sortie de SC
C[0]=faux;
Hors SC;
Fin

Processus P1
tant que (vrai)faire
//entrée en SC
C[1]=vrai;T=0;
tant que (C[0] and T==0); //attente en cas de conflit
Section_critique;
//sortie de SC
C[1]=faux;
Hors SC;
Fin

Remarque : Généralisation sur N processus est possible pour Peterson

Algorithme de lamport (L'algorithme de la boulangerie) : Lamport propose une


solution pour N processus
Algorithme

var choosing : array[0..n-1] of boolean;

number : array[0..n-1] of integer;

7
begin
choosing[0..n-1]:=faux;
number[0..n-1] := 0;
process Pi(1..n)
while (true)do{
{ choosing[i] := vrai;
number[i] := max(number[0], ..., number[n-1])+1;
choosing[i] := faux;
for (j:=0 to n-1)
{ while choosing[j] do /*rien*/;
while (number[j]!=0) and
((number[j],j)<(number[i],i)) do /*rien*/;
}
.... section critique
number[i] := 0;
.... section non-critique
};
}
end

Remarque: Le problème de toutes les approches décrites ci-dessus est : qu’elles mettent en
œuvre des mécanismes d’attente active : les processus désirant entrer en section critique
consomment énormément de ressource processeur, et font un usage intensif du bus mémoire.

Il faut donc mettre en œuvre des mécanismes d’exclusion mutuelle qui bloquent les processus
en attente.

6. Solutions d’attente passive :


Les primitives SLEEP &WAKEUP : SLEEP (dormir) est un appel système qui
suspend l’appelant en attendant qu’un autre processus le réveille(WAKEUP)
.l’appel WAKEUP à un seul paramètre : le processus à réveiller .les primitives
SLEEP&WAKEUP ont chacun, en alternance, un paramètre qui est l’adresse
mémoire utilisée pour faire correspondre les SLEEPs et les WAKEUPs.
 Exemple d’utilisation (le problème de producteur et du consommateur ): Le
problème du Producteur et du Consommateur met en relation deux classes de processus
qui communiquent par l'intermédiaire d'un tampon. La communication leur permet de
coopérer. Pour illustrer le fonctionnement, supposons qu'il y ait 1 Producteur et 1
Consommateur, séparés par une table. Le Producteur produit des objets et les dépose à
mesure sur la table, s'il y a de la place. Le Consommateur prend les objets sur la table,
s'il y en a, et les consomme. Lorsque la table est pleine, le Producteur doit attendre,
pour déposer, qu'une place soit libérée. Lorsque la table est vide, le Consommateur doit
attendre, pour prélever, qu'un objet y soit déposé.
– Un producteur doit arrêter de produire quand il n’a plus de place pour stocker ce
qu’il produit.

8
– Un consommateur doit arrêter de consommer des choses quand le tampon est
vide.
 La solution avec les primitives SLEEP&WAKEUP

Initialisation
N : taille de tampon
Compteur : indice de nombre d’objets dans le tampon =0 ;

Producteur Consommateur
Int objetP
Int objetM ;
While (true) { While(true) {

Produire-objet(&objetP) If(compteur ==O) SLEEP() ;


If(compteur==N) SLEEP() ; Retirer-objet (&objetM);
Mettre-objet(objetP) ; Compteur=compteur-1 ;
Compteur= compteur+1 ; If (compteur==N-1) WAKEUP
If (compteur==1) (producteur) ;
WAKEUP(consommateur) ; Consommer-objet (objetM) ;
} }

9
Les sémaphores
(Solution d’attente passive)

I. Introduction :
Un sémaphore sem est une structure système composée d’une file d’attente f(s)
de processus et d’un compteur C(s), appelé niveau du sémaphore et contenant
initialement une valeur C0(s). Cette structure ne peut être manipulée que par trois
opérations P(sem), V(sem) et init (sem, C0(s)). Ces trois opérations sont des
opérations indivisibles c'est-à-dire que l’exécution de ces opérations s’effectue avec
interruptions masquées et ne peut être interrompue.
II. Les opérations sur les sémaphores :

a) L’opération init :

Elle a pour but d’initialiser le sémaphore, c'est-à-dire qu’elle met à vide la file d’attente f(s) et
initialise avec la valeur C0(s) le compteur C(s). on définit ainsi le nombre de jetons initiaux
dans le sémaphore.

Init (sémaphore sem, entier C0)


Début
Masquer-it ;
Sem.C :=C0 ;
Sem .F :=0 ;
Démasquer-it ;
fin

b) l’opération P(s) :L’opération P(s) attribue un jeton au processus appelant s’il en reste
au moins un et sinon bloque le processus dans la file f(s). L’opération P est donc une
opération éventuellement bloquante pour le processus élu qui l’effectue. Dans le cas
du blocage, il y a ré ordonnancement et un nouveau processus prêt est élu.
Concrètement, le compteur C(s) du sémaphore est décrémenté d’une unité. Si la
valeur du compteur devient négative, le processus est bloqué.
S : sémaphore
P(S) : Début
Masquer-it
S.C=S.C-1;
If( S.C<0) alors
début
État(Pi):= bloqué;
Mettre Pi dans S.F //file des
processus bloqué sur S
démasquer-it ;Fin

10
c) L’opération V(s) :

L’opération V(s) a pour but de rendre un jeton au sémaphore. De plus, si il


y a au moins un processus bloqué dans la file d’attente f(s) du sémaphore,
un processus est réveillé. La gestion des réveils s’effectue généralement en
mode FIFO. L’opération V est une opération qui n'est jamais bloquante
pour le processus qui l’effectue.

V(s) :
Début
Masquer-it
S.C :=S.C+1
Si S.C<=0 alors
Début
Sortir P(en-tête) de S.F
Etat (P) :=actif
fin
démasquer-it
fin

Remarque : On dit qu'un sémaphore est binaire si son compteur ne peut prendre que les
valeurs 0 ou 1,Si Val(S) est initialise a 1 alors la section critique est exécutée en
Exclusion mutuelle.

III. L’exclusion mutuelle à l’aide des sémaphores : Sémaphores d'Exclusion Mutuelle : But
: protéger l'accès à une ressource unique.
 Exemple :
Soient N processus se partageant une ressource critique. Un processus Pi s'écrira :
Contexte commun :

Mutex : sémaphore initialisé à 1 ;


Processus Pi
Début
Première partie du programme ;
P(Mutex)
Appel de la procédure A {section critique }
V(Mutex)
Reste du programme ;
Fin

IV. Désavantage:

Motivation = les sémaphores peuvent être utilisés pour résoudre à peu près n’importe quel
problème d’exclusion mutuelle ou synchronisation . . . mais, les sémaphores possèdent
certains désavantages:
 mécanisme qui demande une discipline sévère dans la façon dont ils sont
Utilisés, sous peine d’erreurs: que se passe-t-il si on oublie d’indiquer un appel `a V? Ou si

11
On effectue une action P en trop?
 Mécanisme sans localisé: un sémaphore doit être connu et accessible par tous les
processus qui pourraient devoir l’utiliser doit être une variable globale tout le programme
Doit être examiné pour voir ou et comment le sémaphore est utilisé

 Le rôle d’une opération P ou V (exclusion mutuelle? synchronisation conditionnelle?)


dépend du type de sémaphore, de la façon dont il est initialisé et manipulé par les divers
processus .

V. Type des sémaphores :


1) Le sémaphore de comptage : Un sémaphore de comptage( généralisé ) a une valeur
entière positive ou nulle.
 (prendre la sémaphore) P(s) teste s > 0. Si oui, on décrémente s. Sinon l’instruction
attend sur s.

 (libérer le sémaphore) V (s) réveille un processus en attente sur s s’il existe un tel
processus, sinon on incrémente s

2) Le sémaphore binaire :
Un sémaphore binaire revient donc à considérer un sémaphore initialisé à 1.
Un sémaphore binaire est un sémaphore ayant une valeur entière entre 0 et 1.
un sémaphore binaire peut étre plus simple à implémenter qu’un sémaphore de
comptage(généralisé) Pour implémenter un sémaphore généralisé (comptage) avec des
sémaphores binaires nous avons besoin des structures de données suivantes :

Var S1, S 2, S 3 : sémaphore binaire

C : integer ;

P(S): V(S):
Debut Debut
P(S3) P (S1)
C:=C+1;
P(S1) If C<=0 then V(S2);
C:=c-1; V S1 ;
If c<= 0 then
Begin End
V(S1)
P( S2)
End
Else

V(S1)
V(S3)
End

12
3) Sémaphores privés:
Un sémaphore ne contient qu’un compteur, c’est parfois insuffisant pour exprimer le
contrôle d’un problème concurrent.
Dans le schéma des sémaphores privés, l’action de synchronisation est associée non plus à
une ressource mais à un processus. La condition de blocage peut alors être propre au
processus

Définition : un sémaphore privé spriv d’un processus Pi est tel que seul Pi peut exécuter
P(spriv) et V(spriv) ,les autres processus ne peuvent exécuter que V(spriv)

 la valeur initiale du sémaphore doit être 0 : C0(spriv,0)


 la file d’attente d’un sémaphore privé contient au plus un processus
 la valeur d’un sémaphore privé vérifie spriv.C≥-1

 Exemple : schéma clients/serveur

Un processus serveur dont le rôle est d’offrir un service à des processus clients ne peut
s’exécuter que sur demande des clients, il traite une seule demande à la fois.

Contexte commun sémaphore spriv; C(spriv,0);


Processus serveur

tant que vrai faire{

P(spriv);

// service

…fin;}
Processus client1
...
V(spriv);
...
Processus client2
...
V(spriv);
...
Conclusion :
Le sémaphore est un mécanisme qui permet le blocage et le réveil explicites de processus
 Le sémaphore permet d’associer un nombre d’autorisations d’accès disponibles à un objet
partagé
 Le schéma des sémaphores privés permet d’exprimer une condition d’accès propre à un
processus
 Tout paradigme de la concurrence peut être traité par l’emploi de sémaphores
 Le sémaphore est un mécanisme simple et puissant, mais “ dangereux” dans un emploi
non contrôlé

13
Les Moniteurs de Hoare
(Solution d’attente passive)

I. Introduction :

Les sémaphores peuvent être utilises pour resoudre à peu près n’importe quel problème
d’exclusion mutuelle ou synchronisation . . . mais, les sémaphores possèdent certains
désavantages:
Le sémaphore est un mécanisme simple et puissant, mais “ dangereux” dans un emploi non
contrôlé avec le respect des spécifications de comportement : pas de boucle infinie, ni de
blocage ou panne pendant l’utilisation des objets partagés
Problème : si plusieurs processus peuvent exécuter des méthodes sur un même objet, le
problème de gérer l’interaction entre ces processus se pose .

Solution : il faut assurer une certaine atomicité garantissant l’exécution correcte des
opérations (méthodes)

Un mécanisme permettant la mise en attente de processus par rapport à une condition sur
l’état de l’objet partagé est nécessaire.

II. La Définition d’un moniteur :

L’idée des moniteurs est de regrouper dans un module spécial, appelé moniteur, toutes
les sections critiques d’un même problème. Un moniteur est un ensemble de procédures, de
variables et de structures de données. Les processus peuvent appeler les procédures du
moniteur mais ils ne peuvent pas accéder à la structure interne du moniteur à partir des
procédures externes.
 Définition : un moniteur est un outil évolué de synchronisation .un moniteur est une
classe utilisée dans un contexte de parallélisme. Les instances de la classe seront des
objets utilisés simultanément par plusieurs processus.
III. Les éléments de base d’un moniteur :

Un moniteur =

 Des variables d’état : des variables définissant la ressource partagée


 Des procédures internes : utiliser par les procédures externes
 Des procédures externes (points d’entrée) : des procédures permettant la
manipulation de la ressource partagée.
 Des conditions : Une variable de condition est utilisée pour suspendre un
processus jusqu’à ce qu’une certaine condition devienne vrai.
 Une ou plusieurs files d’attentes : une file d’attente pour le moniteur et d’autre
pour chaque condition.
 Des primitives de synchronisation : empty(c), wait( c) , signal(c)
Les variables d’états sont manipulables par les procédures externes seulement.

14
IV. La structure d’un moniteur :

Type nom-moniteur = moniteur


Début
-Déclaration des variables locales
(ressources partagées)
-déclaration et corps des procédures du
moniteur (points d’entrées)
-initialisation des variables locales ;
Fin

V. Contexte et Contraintes d’un moniteur :


 Un seul processus est actif à un instant donné dans le moniteur.
 Chaque entrée (opération) est accessible en exclusion mutuelle.
 Pas de variable exportée, seules les procédures du moniteur sont susceptibles de
manipuler les variables du moniteur.
 Au lieu d’être dispersées dans les différents processus, les sections critiques sont
transformées en opérations (procédures) d’un moniteur.
 La gestion de la section critique est à la charge du moniteur et non pas de l’utilisateur.
Le moniteur est implanté tout entier comme une section critique.
Si le moniteur appelé par un processus pour manipuler une donnée partagée, est occupé, le
processus est placé dans la file d’attente du moniteur. Dès qu’il est libéré, l’un des processus
de la file est choisi et la procédure invoquée est exécutée.

VI. Le moniteur et l’exclusion mutuelle :

L’exclusion mutuelle est supportée de façon implicite: un appel, par un processus, d’une
procédure exportée par le moniteur assure que la procédure sera exécutée de façon exclusive,

C’est- a-dire, au plus un appel d’une procédure du moniteur sera actif a un instant donne.

Pour assurer l’exclusion mutuelle, il suffit qu’il y ait à tout moment au plus un processus
actif dans le moniteur. C’est le compilateur qui se charge de cette tâche. Pour ce faire, il
rajoute, au début de chaque procédure du moniteur un code qui réalise ce qui suit : s’il y a
processus actif dans le moniteur, alors le processus appelant est suspendu jusqu’à ce que le
processus actif dans le moniteur se bloque en exécutant un wait sur une variable
conditionnelle (wait(c)) ou quitte le moniteur. Le processus bloqué est réveillé par un autre
processus en lui envoyant un signal sur la variable conditionnelle ( signal(c) ).

Cette solution est plus simple que les sémaphores et les compteurs d’événements, puisque le
programmeur n’a pas à se préoccuper de contrôler les accès aux sections critiques.

15
VII. Le moniteur et la synchronisation (coopération) :

Les synchronisations doivent être décrites et programmées de façon explicite à l’aide de


variables de condition (condition variables) :
Une variable de condition est utilisée pour suspendre un processus jusqu’à ce qu’une
certaine condition devienne vrai

Les conditions :
Les moniteurs possèdent un type condition. Les variables de ce type ne peuvent être déclarées que
dans un moniteur. Une condition est similaire à un sémaphore. Il y a deux opérations permises avec les
conditions: l'opération wait qui suspend le processus et l'opération signal qui réveille un processus.
Une variable condition est une variable :
 qui est définie à l’aide du type condition;
 qui a un identificateur mais, qui n'a pas de valeur (contrairement à un sémaphore).
 Une condition : ne doit pas être initialisée
 ne peut être manipulée que par les primitives Wait et Signal.
 est représentée par une file d'attente de processus bloqués sur la même cause; est

donc assimilée à sa file d'attente .


a) La primitive Wait : bloque systématiquement le processus qui l'exécute. L'opération wait
suspend le processus (qui exécute la procédure du moniteur contenant le wait) sur la queue
d'attente correspondant à la condition. Remarquez que le wait du moniteur suspend toujours le
processus, ce qui est différent du P-wait des sémaphores où la suspension à lieu seulement si
valeur du sémaphore est <= 0. Une condition n'a pas de valeur. Une condition a seulement une
queue d'attente.
b) La primitive Signal : réveille un processus de la file d'attente de la condition spécifiée, si
cette file d'attente n'est pas vide; sinon elle ne fait absolument rien. L'opération signal
réveille un processus suspendu sur la queue correspondant à la condition. S'il n'y a pas de
processus suspendu, alors l'opération signal n'a aucun effet. Ce comportement est différent du
V-signal des sémaphores qui a toujours un effet. Il réveille un processus s'il y en a un en attente, si
non il incrémente la valeur du sémaphore. Le sémaphore mémorise donc le nombre de V-signal,
ce n'est pas le cas du signal des moniteurs.
c) Empty (condition) : La file associée est-elle vide?
Quand un processus est suspendu sur une condition, il libère (quitte) alors le moniteur et un
autre processus peut ensuite accéder à une procédure du moniteur. Lorsque qu'un processus
P1 exécutant dans le moniteur réveille un autre processus P2 par une instruction signal, il y a

16
alors deux processus qui pourraient s'exécuter dans le moniteur. Il est cependant important
qu'un seul des processus puisse pour suivre son exécution pour assurer l'exclusion mutuelle. Il
y a alors deux choix possible conduisant à deux implantations possibles des moniteurs :

1) le choix N° 1 : le processus qui a effectué l'opération signal, P1, continue son exécution.

( P1 était déjà en train de s'exécuter, il est plus simple de le laisser continuer.)

2) le choix N°2 : le processus réveillé, P2, a accès au moniteur et continue son exécution. P1
pourra continuer son exécution quand P2 aura quitté le moniteur. ( P2 a été réveillé par P1
quand certaines conditions étaient satisfaites, si on attend trop longtemps pour réveiller P2, il
se peut que ces conditions ne soient plus satisfaites. Du point de vue de la vérification de
l'exactitude d'un programme, il est préférable de réveiller le processus immédiatement après
l'instruction signal.)

 Exemple 1 :
Un RDV entre N processus à l’aide des moniteurs

Type Rendez_vous = moniteur


{variables locales }
Var Nb_arrivés : entier ; Tous_Arrivés : condition ;
Procedure Entry Arriver : {procédure accessible aux programmes utilisateurs }
Début
Nb_arrivés = Nb_arrivés + 1 ;
Si Nb_arrivés < N Alors wait(Tous_Arrivés) ;
Signal(Tous_Arrivés);
Fin
Début {Initialisations }
Nb_arrivés = 0;
Fin.
Les programmes des processus s'écrivent alors :
Processus Pi
{...............
Rendez_vous.Arriver ; {Point de rendez-vous qui sera bloquant si au moins n'est pas arrivé
au point de rendez-vous }

………..
}
Exemple 2 : Le repas des philosophes à l’aide des moniteurs

Type RepasPhilosophes = moniteur


type Statut =(pense, demande, mange);
Var Statut état[5];
Condition AMoi[5];
{procédures accessibles aux programmes utilisateurs }
Procedure Entry Prendre(entier i);

17
Début
état[i]=demande;
si (état[(i+1)%5]≠mange et état[(i-1)%5]≠mange)
alors état[i]=mange;
sinon AMoi[i].Wait; finsi;
Fin
Procedure Entry Rendre(entier i);
Début
état [i]=pense;
{réveil éventuel d’un voisin}
si (état[(i+1)%5]=demande et état[(i+2)%5]≠mange)
alors état[(i +1)%5]=mange; AMoi[(i+1)%5].Signal;
sinon
si (état[(i-1)%5]=demande et état[(i-2)%5]≠mange)
alors état[(i-1)%5]=mange; AMoi[(i-1)%5].Signal ;finsi;
finsi;
Fin
Début {Initialisations }
Pour i de 0 à 4 faire état[i]=pense; fait;
Fin
Processus Philosophe i
entier i= numero du processus ;
Début
tant que vrai faire
penser;
RepasPhilosophes.prendre(i);
manger;
RepasPhilosophes.rendre(i);
fait;
Fin

18
La région critique
(Solution d’attente passive)

Introduction :

Les régions critiques ont été définies par Hoare et Brinch-Hansen. L'idée de base est de
regrouper les données à protéger en exclusion mutuelle, de caractériser syntaxiquement ce
groupe, et d'en contrôler l'accès

Les régions critiques constituent des outils de haut niveau permettant de résoudre des
problèmes d'exclusion mutuelle et de synchronisation. Faciles d’utilisation, les régions
critiques sont coûteuses en temps d'exécution.

1. La définition de la région critique :

Nous distinguerons deux sortes de variables:


 les variables qui sont la propriété d'un processus qui peut seul y accéder,
 les variables partagées entre plusieurs processus.

La distinction entre ces deux sortes de variables se fait par le mot clés partagée
(SHARED). On peut indiquer lors d'une déclaration de type que les variables de ce type
sont partagées, et donc, nous le verrons, ne peuvent donc être accédées par les processus
parallèles que de l'intérieur de régions mentionnant ces variables (Une région est une
instruction structurée particulière du langage)
L'idée est de regrouper toutes les instructions manipulant les variables partagées, et
formant donc une section critique, dans des régions mentionnant ces variables.

2. La syntaxe de la région critique : Nous donnerons pour une région critique la syntaxe
suivante:

VAR v : partagée T ;
REGION v DO S /*suite-d'instructions */
END REGION;

La variable est déclarée avec l'attribut partagée (shared) , qui signifie partagée. Cet
attribut limite l'accès à la variable. Le type, noté t, est un type quelconque, et peut être en
particulier un tableau ou un enregistrement (record).

L'instruction region permet l'accès à la variable partagée v. Il est impossible d'accéder à


cette variable en dehors d'une région critique. L'exécution de cette instruction se traduit par
l'exécution de s en exclusion mutuelle. Le seul fait d'écrire region v provoque l'entrée en
exclusion mutuelle, et la sortie sera également automatique après l'exécution de s. A la sortie

19
de l'exclusion mutuelle, si des processus sont en attente sur cette variable, ils seront relancés
automatiquement.

de l'exclusion mutuelle, si des processus sont en attente sur cette variable, ils seront relancés
automatiquement

Exemple1 :

REGION compteur DO

compteur ++;

END REGION;

Exemple 2:

REGION compteur DO

compteur --;

END REGION;

Syntaxes 2:

var v1, v2, ..., vn : partagées T;

ressource R : v1, v2, ..., vn

region R do S ;

Les avantages de cette présentation syntaxique sont :

 Pour synchroniser des processus, il faut utiliser une variable partagée (relance
automatique). Donc, tout accès à cette variable est protégé par une exclusion
mutuelle ;
 La lisibilité est bien meilleure qu'avec les méthodes précédentes ;
 Le compilateur évite de nombreuses erreurs (mauvais appariement de P et V,
blocage en section critique...)
3. La région critique et l’exclusion mutuelle : Il y automatiquement en entrée d'une région
demande d'exclusion mutuelle, et en sortie libér .Pendant l’exécution de ≪S≫ aucun autre
processus ne peut accéder la ressource Ration de l'exclusion. équivalente à :

P(mutex) ;

S;

V(mutex) ;

20
4. La région critique et la synchronisation :
Les régions critiques ne permettent pas de synchronisation conditionnelle , Pour y
arriver on ajoute un énoncé « when »
 La région critique conditionnelle :
Syntaxe1 : region v when b do s ;
Syntaxe 2 : var v1, v2, ..., vn : T;
ressource R : v1, v2, ..., vn

region R when B do S
Le processus qui l'exécute entre en section critique ; il calcule la valeur de
l'expression booléenne b :
 L’´évaluation de B et l’exécution de S sont ininterruptibles.
 Si B est faux, on bloque le pcs et on relâche l’exclusion
Mutuelle
il faut noter que :

 les régions critiques, tout comme les sémaphores, font partie du texte des processus ;
 lorsqu'un processus a été bloqué sur condition fausse, sa réactivation répand de
l'évolution des variables dans les autres régions. Sans une analyse fine du contenu des
régions, il faut le réactiver à chaque fois qu'un processus sort d'une région critique sur
la même variable, refaire le test et, si la condition est toujours fausse, le ré bloquer

 Exemple : philosophe

var Etat : partage table [0..4] des entiers ; // déclaration

region Etat // initialisation


do for (int i = 0; i < 5; i++)
Etat[i] = P;

processus Philosophe
while(true)
{
Penser;
region Etat
when Etat [(i-1) mod 5] <> M and Etat [(i+1) mod 5] <> M
do Etat [i] := M;
Manger;

5. Région conditionnelle avec wait :

Dans la structure conditionelle, l'expression booléenne est exécutée avant la séquence s.


Dans certains cas, ceci n'est pas adapté. Une forme plus générale permet de placer l'expression
booléenne n'importe où, entre des instructions non conditionnelles. On introduit une

21
instruction notée wait, qui met le processus en attente inconditionnelle. Cette instruction peut
se placer n'importe où à l'intérieure de la séquence s :

Region v do begin

i1 ;

wait ;

...

in ;

end ;

Les instructions placées avant wait sont exécutées en exclusion mutuelle. Ensuite, le
processus est sorti de l'exclusion mutuelle puis suspendu par wait. Lorsqu'il est relancé, il est
replacé en exclusion mutuelle, exécute les instructions qui suivent wait, puis sort de
l'exclusion mutuelle.

L'instruction wait peut être contrôlée par une expression booélenne :

Region v do

begin

if not b wait ;

s;

end ;

22

Vous aimerez peut-être aussi