0% ont trouvé ce document utile (0 vote)
56 vues16 pages

Programmation Multi-Threading POSIX

Le document décrit la programmation multi-thread avec les threads POSIX. Il présente les concepts de base des threads POSIX, les primitives de création et de terminaison des threads, ainsi que les mécanismes de synchronisation tels que les mutex et la jointure des threads.

Transféré par

Mariem Sayedi
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
56 vues16 pages

Programmation Multi-Threading POSIX

Le document décrit la programmation multi-thread avec les threads POSIX. Il présente les concepts de base des threads POSIX, les primitives de création et de terminaison des threads, ainsi que les mécanismes de synchronisation tels que les mutex et la jointure des threads.

Transféré par

Mariem Sayedi
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

07/03/2024

Programmation Système sous UNIX


2ème Ingénieur Informatique

Chapitre 4. Programmation
Multi-Threading POSIX

H.KRICHENE ZRIDA 1

Programmation avec les Pthreads:

1. Thread POSIX: Création et Terminaison

2. Sémaphores POSIX

3. Variables conditions et Moniteurs


POSIX

H.KRICHENE ZRIDA 2

1
07/03/2024

Threads POSIX Processus Léger


➢ Un processus classique est constitué d'un espace d'adressage avec
un seul fil d'exécution→ ce fil d'exécution étant représenté par
une valeur de compteur ordinal et une pile d'exécution.
➢ Un processus léger (ou encore un Thread) est un espace
d'adressage dans lequel plusieurs fils d'exécution peuvent évoluer
en parallèle. Ces fils d'exécution sont chacun caractérisés par une
valeur de compteur ordinal propre et une pile d'exécution privée.

H.KRICHENE ZRIDA 3

Threads POSIX Processus Léger

☺L’avantage lié à la notion de processus léger est un


allègement des opérations de commutations de
contexte; ➔ en effet lorsque le processeur commute
d'un fil d'exécution à un autre fil et que ces deux fils
(Thread) appartiennent au même espace d'adressage,
alors la commutation est très allégée puisqu'elle
consiste seulement à changer de pile et de valeur de
compteur ordinal, le contexte mémoire restant le
même.
 Un inconvénient majeur est que l'espace d'adressage
est complètement partagé entre tous les fils d'exécution
qui évoluent au sein de celui-ci et donc les opérations de
synchronisation sont plus souvent requises.
H.KRICHENE ZRIDA 4

2
07/03/2024

Threads POSIX Primitives de création de threads (1)


❑int pthread_create (pthread_t *thread, const
pthread_attr_t *attr, void * (*start_routine)(void *),
void *arg) : un thread, identifié par l'identificateur
"*thread", est créé et attaché à l'exécution de la
routine (*start_routine),
❑int pthread_join ( pthread_t thread, void **value_ptr) :
permet au thread principal d'attendre la terminaison
de ses fils et stocke la variable de retour dans
value_ptr. → Si nous ne sommes pas intéressés par le
retour de la fonction exécutée par le thread nous
pouvons mettre NULL
❑int pthread_exit (void **value_ptr) : terminaison du
processus léger
H.KRICHENE ZRIDA 5

Threads POSIX Primitives de création de threads (2)


#include <pthread.h>
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void*),
void *arg);
➢ Les arguments :
– l'argument thread est l'adresse d'un pthread_t ou
"pthread_create" va stocker le numéro du thread créé.
– attr est pointeur sur pthread_attr_t qui permet de définir le
comportement du thread. Si on y place NULL, les attributs par
défauts seront utilisés.
– start_routine est un pointeur de fonction de type void *(*)(void*).
C’est-à-dire que c'est l'adresse d'une fonction qui reçoit un
pointeur non typé et renvoie également un pointeur non typé.
– arg est l'argument transmis à la fonction start_routine.
➢ La fonction pthread_create renvoie 0 si il n'y a pas eu d'erreur.
H.KRICHENE ZRIDA 6

3
07/03/2024

Threads POSIX Création thread POSIX


❑ Pthread: Bibliothèque normalisée POSIX ➔ Fichier d’entête:
« pthread.h »
Pthread_win32: existe sous Windows
❑ Compilation et édition des liens: gcc app.c –lpthread
❑ Déclaration d’un thread: pthread_t thread;
❑ Création d’un thread:

H.KRICHENE ZRIDA 7

Threads POSIX Exemple

H.KRICHENE ZRIDA 8

4
07/03/2024

Threads POSIX Exemple avec passage d’arguments

H.KRICHENE ZRIDA 9

Threads POSIX Exemple Multi-threading

#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
void* f_th(void* n){
printf("Je suis le %d ème thread d'identité
%d.%p\n", *(int *)n, getpid(), (void *)
pthread_self());
pthread_exit(0);
}

H.KRICHENE ZRIDA 10

5
07/03/2024

Threads POSIX Exemple Multi-threading


int main(){
int i; int T[3]; pthread_t th_id[3];
/* création de trois threads */
for(i=0; i<3; i++){
T[i] = i+1;
if (pthread_create(&th_id[i], NULL, f_th, &T[i])== -1){
printf("Erreur creation de thread %d\n", i); exit(0);}
}
printf("Je suis le thread principal %d.%p \n", getpid(), (void *) pthread_self());
printf("Debut attente des threads\n");
/* Attendre la fin de leur exécutions */
for(i=0; i<3; i++) pthread_join(th_id[i], NULL);
printf("Fin de l'attente des threads \n");
return 0 ; }
H.KRICHENE ZRIDA 11

Threads POSIX Jointure


❑ La jointure permet à un thread d’attendre qu’un autre se termine.
Elle se fait via une fonction bloquante: pthread_join
❑ Le thread terminé peut retourner une valeur au thread ayant
effectué la jointure

H.KRICHENE ZRIDA 12

6
07/03/2024

Threads POSIX Jointure : Exemple1

H.KRICHENE ZRIDA 13

Threads POSIX Jointure : Exemple2

H.KRICHENE ZRIDA 14

7
07/03/2024

Mode de création des threads:


Threads POSIX
JOINABLE ou DETACHED
❑ Si le thread est créé en mode JOINABLE ➔ le processus
qui a créé ce thread attend la fin de celui-ci en restant
bloqué sur l'appel à pthread_join. ➔ Lorsque le thread se
termine, les ressources mémoire du thread sont libérées
grâce à l'appel à pthread_join
Si cet appel pthread_join n'est pas effectué, la mémoire
n'est pas libérée et il s'en suit une fuite de mémoire
❑ Pour éviter un appel systématique à pthread_join ➔ on
peut créer le thread en mode DETACHED ➔ Dans ce cas,
la mémoire sera correctement libérée à la fin du thread.

H.KRICHENE ZRIDA 15

Mode de création des threads:


Threads POSIX
JOINABLE ou DETACHED
❑ Il suffit donc de procéder comme suit:

H.KRICHENE ZRIDA 16

8
07/03/2024

Threads POSIX Terminaison


❑ La terminaison d’un thread peut être exécutée depuis:
➢ Le thread lui-même : auto-terminaison via return value; ou void
pthread_exit(void *value) ➔ cette fonction met fin au thread et retourne
value au thread attendant grâce à une jointure (pthread_join( )).
➢ Un autre thread: via pthread_cancel( )

H.KRICHENE ZRIDA 17

Sémaphore binaire (Mutex) POSIX


❑ Un Mutex est un sémaphore binaire pouvant prendre un des deux
états: « lock » (verrouillé) ou « unlock » (déverrouillé): valeur de
sémaphore 1 ou 0
❑ Un mutex ne peut être partagé que par des threads d’un même
processus.
❑ La déclaration d’un mutex: pthread_mutex_t monmutex =
THREAD_MUTEX_INITIALIZER;
❑ Un mutex peut également être initialisé par un appel à: int
pthread_mutex_init(pthread_mutex_t *mutex, const
pthread_mutexattr_t *mutexattr);
Exemple: pthread_mutex_init(&monmutex, NULL); //NULL→ a vec une i nitialisation par
défaut
❑ Un mutex peut être verrouillé par la primitive: int
pthread_mutex_lock(pthread_mutex_t *mutex); ➔ Si le mutex est
déjà verrouillé par un autre thread la tentative de verrouillage
suspend l’appelant jusqu’à ce que soit déverrouillé,
H.KRICHENE ZRIDA 18

9
07/03/2024

Sémaphore binaire (Mutex) POSIX


❑ Un mutex peut être déverrouillé par la primitive: int
pthread_mutex_unlock(pthread_mutex_t *mutex); ➔ Si le mutex
est verrouillé, un des threads en attente obtient le mutex et
redevient actif. Cette opération est toujours bloquante pour
l’appelant.
❑ Exemple:

H.KRICHENE ZRIDA 19

Sémaphore POSIX
❑ Un sémaphore Posix est un sémaphore à compte pouvant être
partagé par plusieurs threads de plusieurs processus.
❑ La prise d’un sémaphore dont le compteur est négatif ou nul
bloque l’appelant.
❑ La Bibliothèque normalisée POSIX est : semaphore.h
❑ Un sémaphore est initialisé par la primitive:

H.KRICHENE ZRIDA 20

10
07/03/2024

Sémaphore POSIX
❑ Les deux opérations génériques P et V sont implémentées par:

❑ Il existe également une version non bloquante de la primitive P:

❑ La primitive suivante retourne dans sval la valeur courante du


sémaphore sem:

❑ La primitive suivante permet de libérer les ressources associées au


sémaphore sem:

H.KRICHENE ZRIDA 21

Exemple de Prod/Cons avec Sémaphore POSIX

H.KRICHENE ZRIDA 22

11
07/03/2024

Exemple de Prod/Cons avec Sémaphore POSIX

H.KRICHENE ZRIDA 23

Exemple de Prod/Cons avec Sémaphore POSIX

H.KRICHENE ZRIDA 24

12
07/03/2024

Moniteurs POSIX
❑ Le moniteur est un concept proposé pour résoudre le problème
de synchronisation.
❑ Les procédures du moniteur se synchronisent à l’aide de deux
primitives : wait( ) et signal( ) qui permettent de bloquer ou de
réveiller un processus sur une condition.
❑ Une condition est une variable qui n’a pas de valeur mais qui est
implémentée à l’aide d’une file d’attente.
❑ Syntaxe des primitives:
➢ Cond.Wait(): bloque toujours le processus appelant
➢ Cond.Signal(): réveille un processus bloqué dans la file d’attente
associé à Cond, H.KRICHENE ZRIDA 25

Moniteurs POSIX
❑ La réalisation d’un moniteur POSIX nécessite:
➢ Un mutex pour assurer l’exclusion mutuelle
➢ Chaque procédure du moniteur est parenthésée par : pthread_mutex_lock()
et pthread_mutex_unlock().
➢ Chaque variable de condition est une variable pthread_cond_t.

➢ Le thread réveillé n’est pas activé immédiatement par pthread_cond_signal()


➔ Généralement, il faut réévaluer la condition de blocage (avec emploi d’un
‘while’ plutôt qu’un ‘if’).

❑ Les primitives sur les conditions:


➢ pthread_cond_wait(&LaVariableCondition, &LeMutex); → Mise en attente
sur une condition et sortie de mutex, → Reprise du mutex au réveil.

➢ pthread_cond_signal(&LaVariableCondition); → Réveil sur une condition.


H.KRICHENE ZRIDA 26

13
07/03/2024

Moniteurs POSIX
❑ La réalisation d’un moniteur POSIX nécessite:
➢ Un mutex pour assurer l’exclusion mutuelle
➢ Chaque procédure du moniteur est parenthésée par : pthread_mutex_lock()
et pthread_mutex_unlock().
➢ Chaque variable de condition est une variable pthread_cond_t.

➢ Le thread réveillé n’est pas activé immédiatement par pthread_cond_signal()


➔ Généralement, il faut réévaluer la condition de blocage (avec emploi d’un
‘while’ plutôt qu’un ‘if’).

❑ Les primitives sur les conditions:


➢ pthread_cond_wait(&LaVariableCondition, &LeMutex); → Mise en attente
sur une condition et sortie de mutex, → Reprise du mutex au réveil.

➢ pthread_cond_signal(&LaVariableCondition); → Réveil sur une condition.


H.KRICHENE ZRIDA 27

Exemple de Prod/Cons avec Moniteur POSIX

H.KRICHENE ZRIDA 28

14
07/03/2024

Exemple de Prod/Cons avec Moniteur POSIX

H.KRICHENE ZRIDA 29

Exemple de Prod/Cons avec Moniteur POSIX

H.KRICHENE ZRIDA 30

15
07/03/2024

Exemple de Prod/Cons avec Moniteur POSIX

H.KRICHENE ZRIDA 31

16

Vous aimerez peut-être aussi