Olivier Lemer
Définition
Situation lors de laquelle un bloc d'opérations ne doit être éxecuté que par un processus à la fois.
Ce bloc d'opérations est appelé Section Critique (SC).
Synchronisation nécessaire
Exemple
Copie synchronisée d'un même compte en banque. Certaines opérations doivent être séquentielles.
synchronized {
}
Section Critique
Exemple inspiré de la syntaxe Java
A
request
accept
release
}
synchronized {
En dehors
En attente
En SC
En dehors
A
request
accept
release
Controller
X
On request
Push demandeur dans la file
On release
Pop tête de file
Envoi de accept
à nouvelle tête
La tête de la file est toujours celle actuellement en SC.
push(A)
pop()
pop()
X A
A
.
release
(from X)
File d'attente
X
en SC
A
ensuite.
B
A
C
C B
push(B)
B
pop()
.
pop()
.
pop()
B
pop()
C B
push(B)
C B
push(B)
B
pop()
.
pop()
release
request
request
C
C
C
release
release
On request
Push demandeur dans la file
On release
Pop tête de file
Si je suis nouvelle tête, entrer en SC.
La tête de la file est toujours celle actuellement en SC.
Problème ?
C
request
release
B
pop()
release
.
pop()
B
C B
push(B)
B
A
C
A
A
A
request
request
request
request
A B
A
B
A C
A B C
A B C
A C B
B
C
B C
C B
release
B
A
C
A
A
A
request, 2
request, 2
request, 2
request, 2
A B
A
B
A C
2 2
2 2
2 2
A B C
A B C
A B C
2 2 2
2 2 2
2 2 2
B
C
B C
B C
2 2
2 2
2 2
release, 4
t=1
t=1
t=1
Reorder par les estampilles
Ajout d'une estampille
Envoi de son estampille avec.
Sauvegarde des estampilles reçues
Problème ?
Trie la file par heure de Lamport.
On request
Push demandeur dans la file
On release
Pop tête de file
La tête de la file est toujours celle actuellement en SC.
Si je suis nouvelle tête, entrer en SC.
avec son timestamp.
(avec résolution arbitraire des égalités)
C
A
request, 2
request, 2
t=1
release, 4
B C
2 2
A B C
2 2 2
A C
2 2
B
A
C
.
.
.
request, 2
request, 2
request, 2
request, 2
B
B
C
2
2
2
B C
B C
C B
2 2
2 2
2 2
t=1
t=1
t=1
Reorder ?
Problème :
Ils assurent seulement qu'un ordre strict sera obtenu un jour.
Les timestamps de Lamport n'ordonnancent pas les messages immédiatement.
Je suis la tête !
Je suis la tête !
Question
Quand être sûr que mon message a été reçu par tout le monde ?
Un message avec estampille t
dit "cet événement a eu lieu à l'heure logique t
".
B
C
.
.
request, 2
request, 2
B
C
2
2
B C
B C
2 2
2 2
t=1
t=1
ack, 3
ack, 3
ack, 3
B C
2 2
B C
2 2
Attente que mon message soit reçu.
Ack plus récent que mon message. Je peux y aller.
Réordonne la file par heure de Lamport.
avec son timestamp.
On request
Push demandeur dans la file
On release
Pop tête de file
La tête de la file est celle actuellement en SC,
Entrer en SC
Envoie ack
avec nouveau timestamp.
si je suis la nouvelle tête, et
que j'ai reçu tous les ack
s.
si elle a reçu un ack de toutes les autres machines.
Problème ?
La structure de donnée n'est plus adaptée
B
C
request, 2
request, 2
t=1
t=1
ack, 3
ack, 3
REL
A B C
REL
REL
1
1
1
REL
A B C
REL
REL
1
1
1
REL
A B C
REQ
REL
1
2
1
REL
A B C
REL
REQ
1
1
2
REL
A B C
REQ
REQ
1
2
2
REL
A B C
REQ
REQ
1
2
2
ACK
A B C
REQ
REQ
3
2
2
ACK
A B C
REQ
REQ
3
2
2
ACK
A B C
REQ
REQ
3
2
2
ACK
A B C
REQ
REQ
3
2
2
Amélioration :
File remplacée par tableau.
Pour chaque processus,
initialement {REL, 1}
, puis
Un processus entre en SC si
REQ
,sauf si ACK
remplacerait REQ
.
ack, 3
ack, 3
strictement la plus petite.
On REQ
On REL
Stocke message dans tableau.
Suggestions ?
On ACK
Après chaque message
Entre en SC, si
REQ
Envoi ack
avec nouveau timestamp.
Stocke message dans tableau.
Stocke message dans tableau,
sauf si un REQ
y est déjà.
To be continued...
Question : Comment être sûr que j'ai le droit d'entrer en SC ?
Entre en SC, si
REQ
Par l'absurde :
REQ
avec un timestamp t1
.p
, serait plus légitime que moi, son REQ
aurait eu un timestamp t2
plus ancien.
REQ
, et le TS de p
dans mon tableau est encore plus petit que t2
.p
dans mon tableau est t2
, qui est plus petit que t1
.t1
n'est pas le plus petit dans mon tableau ; je n'essaie pas d'entrer en SC.Remarque : cette phrase n'est correcte que si j'interdis de remplacer un REQ
par un ACK
. D'où cette règle.
B
A
C
push(B)
pop()
pop()
push(B)
push(B)
pop()
pop()
pop()
pop()
C
C B
B
.
request
request
release
release
release
C
C B
B
.
C
C B
B
.
Controller
A
B
C
←
B
C
D
←
B
C
A
A
B
C
←
D
1
1
3
X Y Z
A
A
X
A
request
accept
release
1
1
3
a.k.a. Algorithme de Lamport
Le timestamp est incrémenté en entrée et sortie de SC,
Au sortir de SC, le processus
REL
à tous, lui-même compris.À la réception d'un REQ
, le processus
ACK
à l'émetteur.À la réception de tout message, le processus
sauf si cela remplacerait un REQ
par un ACK
.
REQ
et a la plus petite heure logique.Pour demander l'entrée en SC, le processus
REQ
à tous, lui-même compris, puis attend.Les N
processus maintiennent un tableau de taille N
, et
un timestamp ts
de Lamport.
et à toute réception de la part d'un autre processus.
Variables
n
self
ts
enSC
tab
entier, constant
entier, entre 0 et n-1
entier, initialement 0
booléen
tableau de messages
nombre de processus
numéro de ce processus
timestamp Lamport de ce processus
vrai ssi autorisé à être en SC
messages de chaque processus
de format {[REQ|ACK|REL], ts}
,
initialement {REL, 0}
.
Initialisation
Écouter infiniment les événements suivants :
Demande de SC de la couche applicative
Passage de enSC
à true
Sortie de SC dans la couche applicative
Réception REQ(ts)
Réception ACK(ts)
Réception REL(ts)
(Avec traitement séquentiel de chaque événement)
Traitement : Sortie de SC dans la couche applicative.
ts
incrémenté.
Envoi de {REL, ts}
à tous les processus, self
inclus.
Traitement : Passage de enSC
à true
.
Autorisation de la couche applicative à entrer en SC.
Traitement : Demande de SC de la couche applicative.
ts
incrémenté.
Envoi de {REQ, ts}
à tous les processus, self
inclus.
Traitement : Réception {REL, tsi}
du processus i
.
Traitement : Réception {REQ, tsi}
du processus i
.
ts
← max(tsi
, ts
) + 1, si i
n'est pas self
.
tab[i]
← {REQ, tsi}
.
Envoi de {ACK, ts}
à i
.
Tentative d'entrée en SC.
ts
← max(tsi
, ts
) + 1, si i
n'est pas self
.
tab[i]
← {REL, tsi}
.
Tentative d'entrée en SC.
Traitement : Réception {ACK, tsi}
du processus i
.
ts
← max(tsi
, ts
) + 1, si i
n'est pas self
.
Si tab[i]
n'a pas comme type REQ
,
tab[i]
← {ACK, tsi}
.
Tentative d'entrée en SC.
Tentative d'entrée en SC.
Si tab[self]
est de type REQ
Extraire toutes les heures logiques dans tab
.
Si la plus ancienne appartient à self
,
enSC ← true
Correctness Jamais plus d'un processus sera en SC à un instant T.
Progrès Toute demande d'entrée en SC sera autorisée un jour.
Complexité
Communication par SC par processus :
Calcul par événement :
3n(n-1
)
O(n
) par réception de message
O(1) pour le reste.
Process i
Application
}
synchronized {
Abstraction mutex
request
release
accept
Abstraction réseau
REQ
ACK
REL
Implémenté comme une couche d'abstraction de mutex.
Couche d'abstraction réseau : indépendance de l'abstraction mutex et du système de communication choisi (tcp, udp, channels, etc).
Suppositions:
A
a un timestamp à 2
,B
a un timestamp à 10
.
A
demandera la SC au bout d'une seconde, et B
au bout de 4s.
Mêmes conditions, mais
Trois processus, et initialement
A
a un timestamp à 10,B
a un timestamp à 6,C
a un timestamp à 4.
Demandes de SC
A
au bout de 1 seconde,Ça fait beaucoup de messages...
Y a-t-il des messages qui peuvent être omis ?
Modifiez le pseudocode en conséquence.
Les cases inchangées sont laissées vides
Un ACK
peut être omis si le message le plus récemment envoyé par l'émetteur est un REQ
. En effet, Si un processus a envoyé un REQ
, alors il sait que tout ACK
qu'il enverra ensuite sera ignoré chez le destinataire, jusqu'à ce qu'il envoie un REL
.
L'algorithme peut donc être changé de manière à ce qu'un ACK
ne soit envoyé que si le tableau ne contient pas de REQ
dans la position self
.