le problème les besoinslig-membres.imag.fr/.../cours/se/3a-synchroetd.pdf · © f. boyer, uga...
Post on 05-Jun-2020
0 Views
Preview:
TRANSCRIPT
1© F. Boyer, UGA Cours de Programmation Concurrente – Info4
4. Mécanismes de base pour la synchronisation F. Boyer, Laboratoire Lig Fabienne.Boyer@imag.fr
■ Le problème■ Les besoins
◆ Exemple de l’application bancaire
■ Les solutions de base◆ Les Sections critiques◆ Les Verrous
2© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Le problème
processus ou threads concurrents
accès concurrents à des ressources partagées
incohérences potentielle
3© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Exemple
4© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Les sections critiques
■ Principe des sections critiques :
◆ On ne sait pas contrôler l’accès à une variable
◆ On peut contrôler l’accès aux instructions qui manipulent la variable, par ajout de code de contrôle
code de contrôle avant instructions de manipulation de variables partagées
code de contrôle après
Section Critique
5© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Sections critiques
■ Élement de synchronisation de base (E.W. Dijkstra)
Le code de contrôle du'une SC doit garantir que: ◆ Lorsqu’un processus est dans une SC, aucun autre ne peut être
dans la même SC
◆ Aucune hypothèse ne doit être faite sur les vitesses relatives des processus et sur le nombre de processeurs
◆ Pas de blocage intempestif
◆ Absence de privation
6© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Sections critiques
■ n threads: T0, T1, .., Tn
■ T0, T1, .., Tn manipulent un ensemble de variables partagées a, b, c, …
■ Structure d’un thread Ti :…<entry section> // code de contrôle avant<manipulation de a,b,c,..> // section critique<exit section> // code de contrôle après…
Remarque : le programmeur peut définir autant de sections critiques que d'ensemble de variables partagées
7© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Essai
Données partagées :int busy= false;
Ti (i=0..N):
while (busy); busy = TRUE;
<critical section>
busy = FALSE;
8© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Algorithme de Dekker (1965)
Données partagées : int turn = 0; int flag[2] = {false, false};
Ti ( i = 0 ou 1) :
flag[i] = TRUE; while (flag[1-i]) { // the other wants to enter if (turn == 1-i) { // it isn't my turn flag[i] = FALSE; while (turn != i); // att. active flag[i] = TRUE; } } <critical section> turn = 1 – i; flag[i] = FALSE;
à Non généralisable à n processus / threads (n > 2)à Non FIFO
9© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Algorithme de Peterson (1981)
Données partagées : int last = 0; int interested[2] = {FALSE, FALSE};
Ti (i = 0 ou 1) :
interested[i] = TRUE; last = i; while (last == i && interested[1-i]) ; // attente active <critical section> interested[i] = FALSE;
Solution à 2 processus généralisable à n processus
10© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Algorithme de Lamport
Données partagées : int number[n+1] = {0,0,0,…}; int choosing[n+1];
Ti (i=0..N):
choosing[i] = TRUE; number[i] = 1 + max(number[0], …, number[n-1]); choosing[i] = FALSE; for (j=1; j<= n; j++) { while (choosing[j]); // wait until j gets a ticket while (number[j] != 0) && // wait while j tries entering if j has a higher prio ((number[j] < number[i]) || (number[j] == number[i]) && j<i))); } <critical section> number[i] = 0;
11© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Solutions
■ Logicielles◆ Complexes
◆ Pas vraiment efficaces
■ Matérielles◆ Masquage des IT◆ Usage de l’instruction Test&Set / Swap
12© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Mise en œuvre des SC par masquage des interruptions
■ Principe◆ Entry section : masquer les IT
◆ Exit section : restaurer les IT
■ Problèmes◆ Solution non utilisable en multiprocesseurs
◆ Temps passé en SC non contrôlable
■ Le masquage est acceptable en mono-processeur si la durée d'exécution du code masqué est courte
13© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Instruction Test&Set (multiprocesseurs)
■ Teste et modifie le contenu d’un mot mémoire de manière atomique (non interruptible)
Equivalent fonctionnel en langage C:
int Test&Set (int *b) { // set b to true, and return initial value of b int res = *b; *b = TRUE; return res; }
14© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Instruction Test&Set
Données partagées : int busy = FALSE;
Pi : … while (Test&Set (&busy)); <critical section> busy = FALSE; …
à Attente activeà Risque de privationà Utiliser un système de ticket pour éviter la
privation
15© F. Boyer, UGA Cours de Programmation Concurrente – Info4
+Instruction Test&Set
typedef struct { int dist_ticket;
int clock; int busy;
} lock;
void initLock(lock *lock){ lock->dist_ticket=0; lock->clock=0;
lock->busy = FALSE; }
void enter(lock *lock){ int my_ticket; while (test&set(&lock->busy))); my_ticket = lock->dist_ticket++; release(&(lock->busy)); while (my_ticket != lock->clock);
} void exit(lock *lock){
while (test&set(&lock->busy))); lock->clock++; release(&(lock->busy));
}
à Allouer un ticket pour éviter la privation
takes a ticket
16© F. Boyer, UGA Cours de Programmation Concurrente – Info4
+Usage
lock l; int cpt = 0; T0: initlock(&l); <create T1 & T2>
T1: … lock (&l); cpt++; unlock(&l); … T2: … lock (&l); cpt++; unlock(&l); …
17© F. Boyer, UGA Cours de Programmation Concurrente – Info4
+Scenario avec T1, T2 et T3
init(&l);T3: enter(&l) ……………………………………..T3: exec SC……………………...………............T1: enter(&l) – loop on while(my_ticket..)…..T2: enter(&l) – loop on while(my_ticket ..).…T3: exit(&l)………………………………………..T1: exec SC………………………………………T1: exit(&l)……………………………………….T2: exec SC……………………………..............T2: exit(&l)………………………………………..
ticket T3
ticket T1
ticket T2
clock
00 00 00 1 00 1 2 0
1 2 11 2 1
2 22 2
3
18© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Instruction Swap
■ Swap : permutation atomique de deux variables.
void Swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; }
19© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Solution à base d’attente passive
■ Problème des solutions précédentes : ◆ gaspillage de l’UC (attente active)
■ Principes des solutions à base d’attente passive :◆ Endormir un processus lorsque la section est
verrouillée◆ Le réveiller lorsqu’elle se libère
à Utilisation de deux primitives fournies par le noyau :à suspend(queue q) et wakeup()
20© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Principes de mise en œuvre des fonctions Suspend et Wakeup
Données partagées proc_ctxt current; proc_ctxt_list ready_queue; void suspend( proc-ctxt_list *queue) { proc_ctxt *old = current; mask(); put_last(queue, current); current= get_first(ready_queue); ctxt_swap(current, old); unmask(); }
void wakeUp(proc_ctxt *p){ mask(); put_last(ready_queue, p); unmask(); }
21© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Les verrous
■ Un verrou est un élément de synchronisation qui ne laisse passer qu’un processus à la fois
■ Généralement à base d’attente passive◆ Sauf pour les spin-locks
■ S’utilise au travers d’une interface◆ lock() // ou enter()◆ unlock() // ou exit()
■ Différentes mise en œuvres à différentes propriétés◆ Verrous de base : utilisation d’une primitive matérielle de synchronisation +
attente passive◆ Sémaphores initialisées à 1◆ Moniteurs / sections critiques conditionnelles mono-condition
22© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Exemple d’usage d’un verrou
int alloc_id () {
lock(&l);
return id++;
unlock(&l);
}
// Données partagées
int id;
lock l;
void init() {
id= 0;
init(&l);
}
23© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Exemple de mise en œuvre d’un verrou
typedef struct {
int busy; // is the lock taken or free
proc_ctxt_list waitings; // waiting processes
} lock;
void init_lock(lock *l) {
mask();
l->busy = FALSE;
init_list(&(l->waitings));
unmask();
}
true
P3 P2
waitings
busy
lock
24© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Exemple de mise en œuvre d’un verrou
void lock(lock *l) {
mask();
if(l->busy)
suspend(&(l->waitings));
l->busy = TRUE;
unmask();
}
void unlock(lock *l) {
proc_ctxt w;
mask();
l->busy = FALSE;
if (w = get_first((&(l->waitings))))
wakeup(w);
unmask();
}
Risque de non-exclusion
25© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Exemple de mise en œuvre d’un verrou
void lock(lock *l) {
mask();
while (l->busy)
suspend(&(l->waitings));
l->busy = TRUE;
unmask();
}
void unlock(lock *l) {
proc_ctxt w;
mask();
l->busy = FALSE;
if (w = get_first((&(l->waitings))))
wakeup(w);
unmask();
}
Risque de privation (PROBLEME DU VOL DE CYCLE)
26© F. Boyer, UGA Cours de Programmation Concurrente – Info4
Exemple de mise en œuvre d’un verrou
void lock(lock *l) {
mask();
if (l->busy)
suspend(&(l->waitings));
l->busy = TRUE;
unmask();
}
void unlock(lock *l) {
proc_ctxt w;
mask();
if (w = get_first((&(l->waitings))))
wakeup(w);
else l->busy = FALSE;
unmask();
}
top related