le problème les besoinslig-membres.imag.fr/.../cours/se/3a-synchroetd.pdf · © f. boyer, uga...

26
1 © F. Boyer, UGA Cours de Programmation Concurrente – Info4 4. Mécanismes de base pour la synchronisation F. Boyer, Laboratoire Lig [email protected] Le problème Les besoins Exemple de lapplication bancaire Les solutions de base Les Sections critiques Les Verrous

Upload: others

Post on 05-Jun-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

1© F. Boyer, UGA Cours de Programmation Concurrente – Info4

4. Mécanismes de base pour la synchronisation F. Boyer, Laboratoire Lig [email protected]

■  Le problème■  Les besoins

◆  Exemple de l’application bancaire

■  Les solutions de base◆  Les Sections critiques◆  Les Verrous

Page 2: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 3: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

3© F. Boyer, UGA Cours de Programmation Concurrente – Info4

Exemple

Page 4: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 5: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 6: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 7: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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;

Page 8: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 9: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 10: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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;

Page 11: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 12: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 13: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 14: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 15: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 16: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 17: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 18: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 19: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 20: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 21: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 22: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

}

Page 23: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 24: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

Page 25: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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)

Page 26: Le problème Les besoinslig-membres.imag.fr/.../cours/SE/3a-synchroETD.pdf · © F. Boyer, UGA Cours de Programmation Concurrente – Info4 2 Le problème processus ou threads concurrents

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

}