Title: Synchronisation Classique
1Synchronisation Classique
- Contexte
- Le problème de la section critique
- Matériel pour la synchronisation
- Sémaphores
- Problèmes classiques de synchronisation
2Contexte
- Accès concurrent à une mémoire partagée peut
produire des incohérences - Maintenir la cohérence des données requière des
mécanismes pour assurer une exécution correcte
des processus coopérants - Une solution mémoire partagée au problème de
tampon borné (bounded buffer) contient un
problème de race condition (condition de
concurrence) sur la variable donnée count.
3Race Condition
- Le Producteur appelle
- while (1)
- while (count BUFFER_SIZE)
- // operation nulle
- // ajouter un element au tampon
- count
- bufferin item
- in (in 1) BUFFER_SIZE
-
4Race Condition
- Le Consommateur appelle
- while (1)
- while (count 0)
- // operation nulle
- // retirer un element du tampon
- count--
- item bufferout
- out (out 1) BUFFER_SIZE
-
5Race Condition
- count peut être implémenté de la façon
suivante register1 count register1
register1 1 count register1 - count peut être implémenté de la façon
suivante register2 count register2
register2 - 1 count register2 - Considérez cette exécution
- S0 producteur exécute register1 count
register1 5S1 producteur exécute register1
register1 1 register1 6 S2
consommateur exécute register2 count
register2 5 S3 consommateur exécute
register2 register2 - 1 register2 4 S4
producteur exécute count register1 count 6
S5 consommateur exécute count register2
count 4
6Solution au Problème de Section Critique
- 1. Exclusion Mutuelle Si le processus Pi est
dans sa section critique, alors aucun autre
processus ne peut exécuter sa section critique - 2. Progression Sil ny a aucun processus dans
la section critique et que des processus veulent
entrer dans leur section critique, alors la
sélection des processus pour entrer en section
critique ne peut pas être retardée indéfininement - 3. Attente Bornée - Une borne doit exister sur
le nombre de fois que les autres processus sont
permis dentrer dans leur section critique après
quun processus ait fait une requête dadmission
en section critique et avant que cette demande ne
soit accordée - Supposer que chaque processus exécute à une
vitesse différente de 0 - Pas dhypothèses concernant les vitesses
dexécution relatives des processus
7Solution pour 2 Tâches
- 2 Tâches, T0 et T1 (Ti et Tj)
- 3 solutions présentées. Toutes implémentent
linterface suivante const
int TURN0 0 const int TURN1 1
void enteringCriticalSection(int turn)
void leavingCriticalSection(int turn)
8Thread Travailleur
- while (true)
- // initialisation des variables partagées
- .
- // demande dentrée en section critique
- enteringCriticalSection(id)
- // section critique
- ...
- // modification des varaibles partagées
- ...
- // sortie de section critique
- leavingCriticalSection(id)
- // section NON critique
-
9Algorithme 1
- Les threads partagent un entier turn
- Si turni, thread i rentre dans sa section
critique - Ne réspecte pas la règle de progession
- Pourquoi?
10Algorithme 1
- // Thread 0turn TURN0
- void enteringCriticalSection(int t)
- while (turn ! t)
- laisser_la_main()
-
- void leavingCriticalSection(int t)
- turn 1 - t
-
11Algorithme 2
- Ajouter plus dinformations sur létat
- Drapeau boléen pour indiquer lintérêt du thread
pour entrer dans la section critique - Règle de progression toujours pas respectée
- Pourquoi?
12Algorithme 2
-
- void enteringCriticalSection(int t)
-
- flag0 true
- while(flag1 true)
- laisser_la_main()
-
-
- void leavingCriticalSection(int t)
-
- flag0 false
-
13Algorithme 3
- Combine les 2 idées précédentes
- Règles respectées?
14Algorithme 3
- // Thread 0
- void enteringCriticalSection(int t)
- int other 1 - t
- turn other
- if (t 0)
- flag0 true
- while(flag1 true turn other)
- laisser_la_main()
-
- void leavingCriticalSection(int t)
-
- flag0 false
-
15Matériel de Synchronisation
- Plusieurs systèmes fournissent un support
matériel pour gérer des sections critiques - Uniprocesseurs bloquer les interruptions
- Le code en exécution sexécute sans préemption
- Générallement pas efficace sur des
multiprocesseurs - OSs utilisant cette technique ne passent pas à
léchelle - Machines modernes fournissent des instructions
spécifiques - Atomiques non-préemptables
- Soit tester un mot mémoire et le modifier
- Ou échanger le contenu de deux mots mémoire
16Structures de Données pour Solutions Matérielles
- typedef struct
-
- boolean data
- HardwareData
- boolean get(HardwareData var)
- return var-gtdata
-
- void set(HardwareData var, boolean data)
- var-gtdata data
-
17Structure de Données pour Solutions Matérielles -
cont
- boolean TestAndSet(HardwareData var)
-
- boolean oldValue get(var)
- set(var, true)
- return oldValue
-
- void swap(HardwareData this, HardwareData
other) - boolean temp get(this)
- set(this, get(other))
- set(other, temp)
-
18Thread Utilisant TestAndSet Verrou
- // Verrou partagé par tous les threads
- HardwareData verrou false
- while (true)
- while (TestAndSet(verrou))
- laisser_la_main()
- sectionCritique()
- set(verrou, false)
- sectionNonCritique()
19Thread Utilisant Instruction swap
- // verrou partagé par tous les threads
- HardwareData verrou false
- // chaque thread a une copie locale de clef
- HardwareData clef true
- while (true)
- set(clef, true)
- do
- swap(verrou, clef)
-
- while (get(clef) true)
- sectionCritique()
- set(verrou, false)
- sectionNonCritique()
-
20Sémaphore
- Outil de synchronisation ne provoquant pas du
busy waiting (attente active)(spin lock) - Semaphore S entier
- Deux opérations standards modifient S acquire()
and release() - A lorigine (Hollandaise) appelées P() and V()
- Moins compliqué
- Peut être accédé via deux opérations indivisibles
(atomiques) - acquire(S)
- while S lt 0
- // no-op
- S--
-
- release(S)
- S
21Sémaphore comme Outil de Synchronisation Général
- Sémaphore de Comptage valeur entière sur un
domaine non restreint - Sémaphore Binaire valeur entière 0 ou 1 plus
simple à implémenter - Connu aussi sous le nom de as verrou dexclusion
- Peut implémenter un sémaphore de comptage S avec
des sémaphores binaires - Fournit lexclusion mutuelle
22Synchronisation avec Sémaphores
- Semaphore sem // initialisé à 1
-
- while (true)
- acquire(sem)
- // section critique
-
- release(sem)
- // section non critique
-
-
23Implémentation Sémaphores
- acquire(S)
- valeur--
- if (valeur lt 0)
- ajouter processus à liste
- bloquer
-
-
- release(S)
- valeur
- if (valeur lt 0)
- supprimer un processus P de liste
- réveiller P
-
-
24Implémentation Sémaphores
- Doit garantir que deux processus ne puissent pas
exécuter acquire() et release() simultanément
sur un même sémaphore - Ainsi limplémentation devient le problème de la
section critique - Peut maintenant avoir de lattente active dans
limplémentation de la section critique - Mais le code de limplémentation est court
- Très peu dattente active si la section critique
est très peu occupée - Les applications peuvent rester longtemps dans
une section critique - Problèmes de performance discutés dans cette
conférence
25Deadlock et Famine
- Deadlock deux ou plusieurs processus en attente
infinie pour un évènement qui ne peut être
provoqué que par un processus en attente - Soient S et Q deux sémaphores initialisés à 1
- P0 P1
- acquire(S) acquire(Q)
- acquire(Q) acquire(S)
- . .
- . .
- . .
- release(S) release(Q)
- release(Q) release(S)
- Famine blocage infini. Un processus peut ne
jamais être repêché de liste des processus
bloqués du sémaphore.
26Problèmes Classiques de Synchronisation
- Problème du Tampon Borné (Bounded Buffer)
- Problème des Lecteurs/Ecrivains
- Problème des Philosophes
27Problème du Tampon Borné
- const int BUFFER_SIZE 5
- Objet bufferBUFFER_SIZE
- int in, out // initialisé à 0
- Semaphore mutex // initalisé à 1
- Semaphore empty // initialisé à BUFFER_SIZE
- Semaphore full // initialisé à 0
-
28Problème du Tampon BornéMéthode insert()
- void insert(Objet item)
- acquire(empty)
- acquire(mutex)
- // ajouter un item au tampon
- bufferin item
- in (in 1) BUFFER_SIZE
- release(mutex)
- release(full)
29Problème du Tampon Bornéremove()
- Objet remove()
- acquire(full)
- acquire(mutex)
- // supprimer un item du tampon
- Objet item bufferout
- out (out 1) BUFFER SIZE
- release(mutex)
- release(empty)
- return item
30Problème du Tampon BornéProducteur
- Objet message
- while (true)
- // des instructions diverses
-
-
- // produire litem insérer dans le tampon
- message produireMessage()
- insert(message)
-
-
31Problème du Tampon BornéConsommateur
-
- Objet message
- while (true)
- // instructions diverses
-
-
- // consommer un item du tampon
- message remove()
-
-
32Problème Lecteurs-Ecrivains Lecteur
- RWLock db
- while (true)
- // instructions diverses
- ...
- acquireReadLock(db)
- // on a maintenant un accès lecture à la base
de données - // lire de la base de données
- // relâcher le verrou
- releaseReadLock(db)
-
-
33Problème Lecteurs-Ecrivains Ecrivain
- RWLock db
- while (true)
-
- acquireWriteLock(db)
- // on a un accès en écriture
- // écrire
- releaseWriteLock(db)
-
-
34Lecteurs-Ecrivains Base de Données
- typedef struct
- int readerCount // initialisé à 0
- Semaphore mutex // initialisé à 1
- Semaphore db // initialisé à 1
- RWLock
-
35Lecteurs-Ecrivains Méthodes Lecteur
- void acquireReadLock(RWLock verrou)
- acquire(verrou.mutex)
- readerCount
- // si je suis le 1er à lire, dire aux autres
- // que la base de données est en train dêtre
lue - if (readerCount 1)
- acquire(verrou.db)
- release(verrou.mutex)
-
- void releaseReadLock(RWLock verrou)
- acquire(verrou.mutex)
- --readerCount
- // si je suis le dernier à lire, dire aux autres
- // que la base de données nest plus lue
- if (readerCount 0)
- release(verrou.db)
- release(verrou.mutex)
36Lecteurs-Ecrivains Méthodes Ecrivain
- void acquireWriteLock()
- acquire(verrou.db)
-
- void releaseWriteLock()
- release(verrou.db)
37Problème des Philosophes
- Données partagées
- Semaphore baguettes5
38Problème des Philosophes (Cont.)
- Philosophe i
- while (true)
- // prendre baguette de gauche
- acquire(baguettei)
- // prendre baguette de droite
- acquire(baguette(i1)5)
- manger()
- // rendre baguette de gauche
- release(baguettei)
- // rendre baguette de droite
- release(baguette(i1)5)
- penser()