• Aucun résultat trouvé

Programmation concurrente Ex´ecution “simultan´ee” de plusieurs parties d’un programme Ex´ecution sur diff´erents thread

N/A
N/A
Protected

Academic year: 2022

Partager "Programmation concurrente Ex´ecution “simultan´ee” de plusieurs parties d’un programme Ex´ecution sur diff´erents thread"

Copied!
35
0
0

Texte intégral

(1)

Programmation concurrente

Ex ´ecution “simultan ´ee” de plusieurs parties d’un programme Ex ´ecution sur diff ´erents thread, process, processeur, machine quasi-parall ´elisme, pseudo-parall ´elisme, Parall ´elisme r ´eel

Distinguer programmation concurrente, parall `ele, et distribu ´ee

(2)

Objectifs et probl `emes

Objectifs:

Parall ´elisme: Acc ´el ´erer l’ ´ex ´ecution d’une application

Concurrence: G ´erer plus efficacement certaines ressources

Distribution: Faire collaborer plusieurs machines instables

G ´enie logiciel: Mieux organiser le code Probl `emes:

Partitionnement: D ´ecomposer en processus

Communication: ´Echanger les donn ´ees `a traiter

Synchronisation: Ne pas se marcher dessus

(3)

Support mat ´eriel d’ex ´ecution concurrente

Un ensemble de processeurs li ´es par un syst `eme de communication Processeurs: homog `enes, mais pas forc ´ement

Communication: cache partag ´ee, m ´emoire partag ´ee, m ´emoires interconnect ´ees par un r ´eseau sp ´ecialis ´e (bus, hypercube, tore, crossbar), r ´eseau ´ethernet, ...

(4)

Mod `eles de communication

Comment les processus communiquent et se synchronisent M ´emoire partag ´ee:

Un seul tas: acc `es mutuel aux donn ´ees des autres

La communication est souvent implicite, li ´ee `a la synchronisation Typiquement une machine SMP ou SMT

Passage de messages:

Chaque processus a son propre tas: les donn ´ees sont exclusives La synchronisation est souvent implicite, li ´ee `a la communication Typiquement un super-ordinateur, ou un syst `eme distribu ´e

(5)

L’illusion d’une m ´emoire partag ´ee

Le mod `ele de communication ne refl `ete pas forc ´ement la technique de communication sous-jacente

Gestion par le compilateur et le syst `eme d’ex ´ecution (partitioning)

Gestion par le syst `eme de pagination (distributed shared memory)

Gestion par le syst `eme de m ´emoire cache (directory)

M ˆeme si il y a une m ´emoire physique partag ´ee, les caches la ... cachent Bien s ˆur, une m ´emoire peut aussi s’utiliser pour envoyer des messages

(6)

The first problems

incr c = swapMVar c (1 + readMVar c) go count 0 = return ()

go count n = do incr count

go count (n - 1) main = do c <- newMVar 0

forkIO (go c 100000)

forkIO (go c 100000)

print (readMVar c)

(7)

The first problems (2 e essai)

incr c = do cv <- readMVar c

swapMVar c (1 + cv) go count 0 = return ()

go count n = do incr count

go count (n - 1) main = do c <- newMVar 0

forkIO (go c 100000)

forkIO (go c 100000)

cv <- readMVar c

(8)

Probl `emes

Le r ´esultat n’est pas 200000:

Entrelacement des diff ´erentes op ´erations

Il y a une condition de course

incr

est une section critique

Il faut assurer l’exclusion mutuelle dans

incr ⇒

¡Synchronisation!

Le r ´esultat n’est toujours pas 200000:

Attendre la fin des autres processus

¡¡Synchronisation!!

¿Combien d’entrelacements possibles?

(9)

Synchronisation

Outils disponibles:

Masquer les interruptions

Mutex:

lock M ... unlock M

S ´emaphores

Moniteur

Dataflow: variables vides/pleines Comment implanter un mutex?

Attente active ou passive

(10)

Mutex

Les mutex veulent garantir l’exclusion mutuelle.

lock M =

while M unlock M =

wait M := false

M := true

lock

s’appelle aussi acquire, et

unlock

s’appelle aussi release.

(11)

Lock lock

lock M1 lock M2

lock M2 lock M1

x1 = x1 - 100 x2 = x2 + 100 x2 = x2 + 100 x1 = x1 - 100

unlock M2 unlock M1

unlock M1 unlock M2

(12)

Lock lock

lock M1 lock M2

lock M2 lock M1

x1 = x1 - 100 x2 = x2 + 100 x2 = x2 + 100 x1 = x1 - 100

unlock M2 unlock M1

unlock M1 unlock M2

¡Deadlock!

Example classique: philosophes d ´emunis

(13)

Concurrent Haskell: dataflow

incr c = do cv <- takeMVar c putMVar c (1 + cv) ...

main = do c <- newMVar 0

forkIO (go c 100000) forkIO (go c 100000)

<magie>

cv <- takeMVar c

print cv

(14)

Attendre un autre processus

Compte `a num ´ero dans une banque Suisse:

incr c n = do cv <- takeMVar c putMVar c (n + cv) depot c n | n > 0 = incr c n

retrait c n = do << waitfor c >= n >>

incr c (- n)

Comment attendre?

(15)

Attente active

retrait c n = do cv <- readMVar c if cv >= n

then incr c (- n) else do yield

retrait c n

Probl `emes:

Gaspillage de CPU

Condition de course

(16)

Attente active correcte

retrait c n = do cv <- takeMVar c if cv >= n

then putMVar c (cv - n) else do putMVar c cv

yield

retrait c n

C’est quand m ˆeme encore de l’attente active

(17)

Attente active: avec mutex

depot c n | n > 0 = do lock M

c = c + n unlock M retrait c n = do lock M

if c >= n

then do c = c - n unlock M else do unlock M

retrait c n

(18)

Attente avec moniteur

Variable de condition C

depot c n | n > 0 = do lock M

c = c + n signal C unlock M retrait c n = do lock M

if c >= n

then do c = c - n unlock M

else do release&wait M C

(19)

Attente avec moniteur

Imbrication

depot c n | n > 0 = do lock M

c = c + n signal C unlock M retrait c n = do lock M

while c < n

release&wait M C c = c - n

unlock M

(20)

Probl `emes pour le compilateur

Certaines optimisations invalid ´ees par les courses

lock L1 lock L2

write B = 1 write A = 1

t1 = read A t2 = read B

write B = 2 write A = 2

unlock L1 unlock L2

(21)

Probl `emes pour le compilateur

Certaines optimisations invalid ´ees par les courses

lock L1 lock L2

write B = 1 write A = 1

t1 = read A t2 = read B

write B = 2 write A = 2

unlock L1 unlock L2

Si le compilateur ´elimine les deux

write .. = 1

¡¡ on peut obtenir

t1 = 0

et

t2 = 0

!!

(22)

Conditions pour ˆetre “sans course”

Une course est un acc `es `a une variable pendant qu’elle est modifi ´ee Pas de course pour les variables non partag ´ees

Pas de course si chaque acc `es est prot ´eg ´e par un mutex Attention `a utiliser le m ˆeme mutex

Chaque mutex prot `ege un ensemble particulier de variables Pas de course

6⇒

correct

(23)

Composition difficile

On veut d ´eplacer de l’argent entre 2 comptes

retrait c1 n depot c2 n

Le moniteur prot `ege retrait et depot

On aimerait maintenir l’ ´etat interm ´ediaire cach ´e Il faut exporter le lock

M

, etc...

(24)

Difficult ´es li ´ees aux mutex

Il est trop facile de les utiliser incorrectement:

Oublis

Usage du mauvais verrou

acquire

sans le

release

correspondant

Appels r ´ep ´et ´es:

acquire(x); ...; acquire (x);

...

Risque d’interblocage

Mauvaises performances si la granularit ´e est trop grossi `ere Mauvaises performances si la granularit ´e est trop fine

(25)

Atomicit ´e

Les mutex sont un outil pour obtenir l’atomicit ´e Pas de course

6⇒

atomique

Monad STM en Haskell:

atomically :: STM a -> IO a newTVar :: a -> STM (TVar a) readTVar :: TVar a -> STM a

writeTVar :: TVar a -> a -> STM ()

(26)

Le retour du compte suisse

depot c n | n > 0

= atomically (do cv <- readTvar c

writeTVar c (cv + n)) retrait c n

= atomically

(do cv <- readTVar c if cv < n

then retry

else writeTVar c (cv - n))

L’op ´eration retry

::

STM

α

correspond `a

release&wait

(27)

Composer les deux

depot c n | n > 0 = do cv <- readTvar c

writeTVar c (cv + n) retrait c n = do cv <- readTVar c

if cv < n

then retry

else writeTVar c (cv - n)

on peut alors faire

atomically (do { retrait c1 n; depot c2 n })

Exporter le lock M sans risque de deadlock ni d’oubli de lock

(28)

Comment ne pas attendre

Autre composition: orElse

::

STM

α →

STM

α →

STM

α retrait’ :: TVar Int -> Int -> STM Bool

retrait’ c n = do {retrait c n; return True}

‘orElse‘ return False

Ou encore

retraitRiche :: [TVar Int] -> Int -> STM () retraitRiche [] _ = retry

retraitRiche (c:cs) n

= retrait c n

‘orElse‘ retraitRiche cs n

(29)

Comment c¸a marche

retry

attend un

unlock

parmis ceux utilis ´es Quels mutex utiliser:

Un gros mutex

Un mutex par variable

Demande au programmeur

Analyse par le compilateur pour inf ´erer des mutex

Synchronisation optimiste

(30)

Synchronisation optimiste

Dans le cas id ´eal, les conflits sont rares

lock

est une op ´eration co ˆuteuse, et conservatrice On peut `a la place, d ´etecter les conflits post-facto

(31)

Synchronisation optimiste

Dans le cas id ´eal, les conflits sont rares

lock

est une op ´eration co ˆuteuse, et conservatrice On peut `a la place, d ´etecter les conflits post-facto

Chaque lecture et ´ecriture note l’ ´etat de la variable

On garde ausi un log des variables acc ´ed ´ees

A la fin d’une transaction, on v ´erifie si l’ ´etat a chang ´e`

Si oui rollback, sinon commit

(32)

Impl ´ementation de STM

Chaque

TVar

contient un num ´ero de version

Chaque lecture stocke la variable et sa valeur dans un log Chaque ´ecriture stocke variable, et valeur dans un log

Ecritures ne changent pas imm ´ediatement les variables´ Commit `a la fin de

atomically

:

acquire (stm_lock);

if (!check_consistency (log))

{ release (stm_lock); free (log); goto start; } perform_updates (log);

release (stm_lock);

(33)

STM: Programmation concurrente facile

Probl `eme Solution

Oublier

lock

..

unlock

Type

STM a

inutile sans

atomically

Usage du mauvais mutex Pas besoin de sp ´ecifier quel mutex

lock

sans

unlock atomically

fait les deux d’un coup

lock

r ´ep ´et ´e/r ´ecursif Type de

atomically

pas “imbricable”

Interblocage Synchronisation optimiste Distinguer vars partag ´ees Type

TVar a

diff ´erent

Rollback impossible Type

STM a

restreint aux cas possibles

(34)

Erreurs impossibles

La synchronisation optimiste introduit de nouvelles erreurs

atomic { atomic {

scale = a+b; a -= n;

c = c / scale; b += n;

} }

(35)

Erreurs impossibles

La synchronisation optimiste introduit de nouvelles erreurs

atomic { atomic {

scale = a+b; a -= n;

c = c / scale; b += n;

} }

¡ si

n = a + b

, alors

scale

peut ˆetre 0 !

Références

Documents relatifs

Puisque la position de la structure d’activation n’est pas n´ecessairement au mˆeme em- placement en m´emoire d’une activation `a l’autre, on ne peut connaˆıtre

Introduction.- En langage C, l’acc`es ` a un ´el´ement d’un tableau peut se faire classiquement par le nom du tableau accompagn´e d’un index, mais aussi par un pointeur

L’instruction delete ptr ; lib`ere la place m´emoire pour un ´el´ement de type type alors que delete [] ptr ; lib`ere la place m´emoire pour le tableau dans son entier, c’est-`

L’inconv´enient essentiel des SSI est que le serveur HTTP doit lire ligne ` a ligne le code HTML de toute page `a renvoyer (tout au moins celles d’un suffixe d´etermin´e tel que

Montrer que A admet une valeur propre double λ a et une valeur propre simple λ b , qu’on d´eterminera.. Retrouver `a l’aide de ces valeurs propres le d´eterminant et la trace

Si cette ´ etape est trop exigeante du point de vue computationnel, on peut approximer le crit` ere ` a minimiser au moyen d’une somme de Riemann.

La strat´ egie SJF peut ˆ etre adpat´ ee pour un mode pr´ eemptif : si un processus plus court que le processus actif arrive dans la file, le processus actif est pr´ eempt´

[r]