Académique Documents
Professionnel Documents
Culture Documents
Plan
Synchronisation
• Verou
• Semaphore
• Moniteur
2
Plan
Synchronisation
• Verou
• Semaphore
• Moniteur
Un thread (ou fil d’exécution en français) est une parie du code d’un programme
(une fonction), qui se déroule parallèlement à d’autre parties du programme.
4
Un thread est une unité d’exécution rattachée à un processus, chargée
d’exécuter une partie du processus.
Lorsqu’un processus est créé, un seul flot d’exécution (thread) est associé au
processus. Ce thread peut en créer d’autres. Chaque thread a :
• un identificateur unique
• une pile d'exécution
• des registres (un compteur ordinal)
• un état...
Le premier intérêt peut être d’effectuer un calcul qui dure un peu de temps
(plusieurs secondes, minutes, ou heures) sans que l’interface soit bloquée (le
programme continue à répondre aux signaux).
• Le processus MS-Word implique plusieurs threads: interaction avec le clavier,
rangement de caractères sur la page, sauvegarde régulière du travail fait
• contrôle orthographe, etc
6
Création des threads: crée un processus léger qui exécute la fonction fonction avec
l'argument arg et les attributs attr, renvoie 0 si l’appel réussit, sinon renvoie
l’identifiant de l’erreur
8
Exemple de création des threads (creation1.c)
10
Exemple : partage des variables
11
12
Passage des paramètres: crée un thread qui dort un nombre de secondes passé en
argument, pendant que le thread principal attend qu’il se termine.
13
Passage des paramètres: crée un thread qui lit une valeur entière et la retourne au
main
14
Comparaison des identifiants de threads
• La fonction retourne 0 si tid1 = tid2
• Une valeur non-nulle sinon
Terminaison d’un thread: termine l’exécution la thread courante avec une valeur
de retour particulière
• Le thread appelant se termine avec une valeur de retour égale a *p_status
• Ce code de retour est accessible par les autres threads a travers la fonction
pthread_join()
15
Plan
Synchronisation
• Verou
• Semaphore
• Moniteur
16
Communication entre les threads: synchronisation sur la terminaison
17
18
Exemple: addition de deux matrices
19
• création de N fils
• chaque fil résout 1/N de la matrice C
• attendons la fin des N fils
• la matrice C peut maintenant être
utilisée
20
Dans un programme qui utilise les threads qui ne sont pas complètement
indépendants, ils doivent communiquer entre eux (com.c)
21
Plan
Synchronisation
• Verou
• Semaphore
• Moniteur
22
Plusieurs processus s’exécutent en pseudo-parallèle ou en parallèle et partagent
des objets (mémoires, imprimantes, etc.).
Le partage d’objets sans précaution particulière peut conduire à des résultats
imprévisibles. L’état final dépend de l’ordonnancement des processus.
La solution au problème s’appelle synchronisation des processus.
• Il faut empêcher les autres processus d’accéder à un objet partagé si un objet
est en train d’être utilisé par un processus, ce qu’on appelle d’assurer
l’exclusion mutuelle.
• Les situations de ce type, où deux ou plusieurs processus lisent ou écrivent
des données partagées et où le résultat dépend de l’ordonnancement des
processus, sont qualifiées d’accès concurrents.
23
Objet critique : Objet qui ne peut être accédé simultanément, les imprimantes, la
mémoire, les fichiers, les variables etc
Section critique : Ensemble de suites d’instructions qui opèrent sur un ou
plusieurs objets critiques et qui peuvent produire des résultats imprévisibles
lorsqu’elles sont exécutées simultanément par des processus différents, i.e., une
séquence d’instructions qui ne peuvent jamais être exécutées par plusieurs threads
simultanément
Somme des premiers nombres en utilisant des processus légers:
• si plusieurs processus exécutent concurremment ce code, on peut obtenir un
résultat incorrect.
• La solution correcte nécessite l’utilisation des sections critiques.
24
Les processus qui exécutent des sections critiques sont structurés comme suit:
• Section non critique.
• Demande d’entrée en section critique.
• Section critique.
• Demande de sortie de la section critique.
• Section non critique.
25
Sémaphore
• gestion de jetons (compteur)
• associé à une file d’attente
• exemple : accès multiples (mais bornés) à une ressource
• Moniteur
26
Plan
Synchronisation
• Verou
• Semaphore
• Moniteur
27
28
Le mécanisme mutex (MUTual EXclusion ) repose sur l’utilisation du type
pthread_mutex_t
Un mutex est une structure de données qui permet de contrôler l’accès à une
ressource. Un mécanisme empêchant deux processus ou plus d'accéder simultanément
à une ressource partagée.
29
Un mutex est une structure de données qui permet de contrôler l’accès à une
ressource. Un mécanisme empêchant deux processus ou plus d'accéder simultanément
à une ressource partagée.
Un mutex qui contrôle une ressource peut se trouver dans deux états :
• Libre (ou unlocked). Cet état indique que la ressource est libre et peut être
utilisée sans risquer de provoquer une violation d’exclusion mutuelle.
• Réservée (ou locked). Cet état indique que la ressource associée est actuellement
utilisée et qu’elle ne peut pas être utilisée par un autre thread.
Les fonctions
• Initialisation: phtread_mutex_t mutex = THTREAD_MUTEX_INITIALIZER;
• Verrouillage: int phtread_mutex_lock(phtread_mutex_t * mutex);
• Déverrouillage: int phtread_mutex_unlock(phtread_mutex_t * mutex);
• Destruction: int pthread_mutex_destroy(pthread_mutex_t * mutex);
30
Un mutex peut être vu comme étant une structure de données qui contient deux
informations :
• La valeur actuelle du mutex ( locked ou unlocked)
• Une queue contenant l’ensemble des threads qui sont bloqués en attente du
mutex
lock(mutex m) { unlock(mutex m) {
if(m.val==unlocked) if(m.queue is empty)
{ {
m.val=locked; m.val=unlocked;
} }
else else
{ {
// Place this thread in m.queue; // Remove one thread(T) from m.queue;
// This thread is blocked; // Mark Thread(T) as ready to run;
} }
} }
31
Problème de synchronisation
32
Exemple: counter (counter1.c) avec deux threads
33
34
Exercice 2
• Soit un tableau M de N éléments rempli par un thread lent et lu par un autre
plus rapide.
• Le thread de lecture doit attendre la fin du remplissage du tableau avant
d’afficher son contenu. Qui ce que vous remarquez. Comment résoudre ce
problème.
35
Exercice 2 (LectureEcritureTab.c)
36
Exercice 2
37
Cinq philosophes sont assis autour d’une table. Sur la table, il y a alternativement
cinq plats de spaghettis et cinq fourchettes:
• Un philosophe passe son temps à manger et à penser.
38
Il est important de signaler que si tous les philosophes prennent en même temps
chacun une fourchette, aucun d’entre eux ne pourra prendre l’autre fourchette
(situation d’interblocage).
Pour éviter cette situation, un philosophe ne prend jamais une seule fourchette. Les
fourchettes sont les objets partagés.
• Chaque fourchette est une ressource partagée qui ne peut être utilisée que par un
philosophe à la fois.
39
Quand un philosophe affamé a ses deux couverts dans les mains en même temps, il
mange sans libérer ses couverts.
Par exemple, dans notre hypothèse d'un dîner de cinq philosophes, seulement deux
philosophes peuvent manger à un instant donné car les couverts ne sont pas suffisants.
Trois philosophes n'ont la possibilité que de penser ou d'être en attente de vouloir manger.
40
Scénario 1:
Les philosophes décident de manger au
même moment:
o Commencent tous par récupérer la
fourchette se trouvant à leur gauche
(resp. droite).
o Sont bloqués en essayant de récupérer
la fourchette à droite (resp. gauche)
(alors qu’il n’y a plus de fourchette sur
la table).
41
Scénarios 1
42
Scénarios 1
43
Scenario 2: forçant les threads à s’approprier les mutex qu’ils utilisent dans le même
ordre
• Ph0: s’approprie d’abord le mutex fourchette[0] et ensuite le mutex fourchette[1]
• Ph1: s’approprie d’abord le mutex fourchette[1] et ensuite le mutex fourchette[2]
• Ph2: s’approprie d’abord le mutex fourchette[2] et ensuite le mutex fourchette[3]
• Ph2: s’approprie d’abord le mutex fourchette[3] et ensuite le mutex fourchette[4]
• Ph4: s’approprie d’abord le mutex fourchette[4] et ensuite le mutex fourchette[0]
Avec cet ordre d’allocation des mutex, un deadlock n’est plus possible
Il y aura toujours au moins un philosophe qui pourra s’approprier les deux baguettes dont
il a besoin pour manger.
Si un des philosophes ne cherche pas à manger, ses deux baguettes sont nécessairement
libres et au moins un de ses voisins philosophes pourra manger.
44
Scenario 2:
45
Scenario 2:
46
Plan
Synchronisation
• Verou
• Semaphore
• Moniteur
47
La concurrence entre les processus peut être traité par l’emploi de sémaphores.
48
Principalement, un processus utilisateur du sémaphore demande un ticket en
invoquant P :
• si au moins un ticket est disponible, le processus appelant le prend et poursuit
son exécution
• sinon, le demandeur est enregistré dans une file d'attente et est bloqué dans
l'attente de l'obtention d'un ticket, l'opération P n'est exécutable par le
processus appelant que s'il existe un ticket libre
49
Un sémaphore peut donc être représenté par un compteur, et une file d'attente de
processus. La file d'attente enregistre les processus demandeurs bloqués, et le
compteur représente :
• quand il est supérieur à 0, le nombre de tickets disponibles et donc le
nombre de processus dont les demandes seront immédiatement
satisfaisantes,
• quand il devient négatif, sa valeur absolue est alors le nombre de processus
bloqués en attente d'un ticket.
50
Les services Posix de manipulation des sémaphores se trouvent dans la librairie
<semaphore.h>
Le type sémaphore est désigné par le type sem_t.
Initialisation d’un sémaphore:
int sem_init(sem_t *sem, int pshared, unsigned int value)
• sem est un pointeur sur le sémaphore à initialiser
• value est la valeur initiale du sémaphore
• pshared indique si le sémaphore est local au processus pshared=0 ou partagé
entre le père et le fils pshared!=0
51
52
Exemple: sem_posix.c
53
L'état des philosophes sera stocké dans un tableau alloué dans un segment de
mémoire partagé
54
Exemple: problème des philosophes, philosophe1.c
55
56
Exemple: problème des philosophes,
philosophe2.c
57
• Pour assurer une certaine cohérence des données de la base, il faut interdire
l’accès (en lecture et en écriture) à tous les processus
o Les rédacteurs représentent les processus qui demandent des accès en
écriture à la base de données
58
Problème des rédacteurs et des lecteurs
• Pour contrôler les accès à la base, on a besoin de connaître le nombre de
lecteurs (NbL) qui sont en train de lire
• Le compteur NbL est un objet partagé par tous les lecteurs.
• L’accès à ce compteur doit être exclusif (sémaphore mutex)
• Un lecteur peut accéder à la base, s’il y a déjà un lecteur qui accède à la base
(NbL>0) ou aucun rédacteur n’est en train d’utiliser la base
• Un rédacteur peut accéder à la base, si elle n’est pas utilisée par les autres (un
accès exclusif à la base)
• Pour assurer cet accès exclusif, on utilise un autre sémaphore : Redact
NbL<-0 // Nb Lecteurs
semaphore Redact // écrivain
semaphore Mutex // accès à la base
59
60
Producteur/consommateur
• Deux processus partagent une mémoire tampon de taille fixe. Les deux
processus ne doivent pas accéder en même temps au tampon
Le producteur
• Met des informations dans la mémoire tampon, et l’autre, les retire
• Peut produire uniquement si le tampon n’est pas plein
• Doit être bloqué tant et aussi longtemps que le tampon est plein
Le consommateur
• Peut retirer un objet du tampon uniquement si le tampon n’est pas vide
• Doit être bloqué tant et aussi longtemps que le tampon est vide
61
Le producteur attend si le
tampon est plein :
P(vide). Il est réveillé dès
que le tampon n’est plus
plein: V(vide)
Le consommateur attend
si le tampon est vide :
P(plein). Il est réveillé
dès que le tampon n’est
plus vide : V(plein)
62
Le sémaphore vide contrôle le nombre de cases vides
Le producteur exécute P(vide) pour réserver une case
Le consommateur exécute V(vide) pour libérer une case
Le producteur exécute V(plein) pour signaler au consommateur 1 nouveau
message dans le tampon
Le consommateur exécute P(plein) pour attendre un message
Pas d’interblocage:
Le producteur et le consommateur
ne peuvent être bloqués simultanément,
respectivement sur P(vide) et P(plein)
63
Exemple: taille 1
Sans synchronisation
Avec synchronisation
64
Plan
Synchronisation
• Verou
• Semaphore
• Moniteur
65
66
Les moniteurs proposent une solution de «haut-niveau» pour la protection
de données partagées.
Seul un processus (ou tâche ou thread) peut être actif à un moment donné
à l'intérieur du moniteur.
67
68
int pthread_cond_signal (pthread_cond_t *cond_wait);
69
Exemple du parking:
70
Exemple du parking:
71
http://queinnec.perso.enseeiht.fr/Ens/SC/precis.pdf
72