Title: Threads Posix.1c/1003b IEEE
1Threads Posix.1c/1003bIEEE
2Présentation
- Un thread est un déroulement d'un programme qui
s'exécute parallèlement à d'autres unités en
cours d'exécution. - Les différents threads d'une application
partagent un même espace d'adressage. L'accès
concurrentiel aux mêmes données nécessite une
synchronisation pour éviter les interférences. - En outre chaque thread dispose d'une pile et d'un
contexte d'exécution contenant les registres du
processeur et un compteur d'instruction. - L'idée générale est de détacher le flot
d'exécution des ressources
3Le contexte processus
Contexte du processus
Code données et pile
- Contexte d'exécution
- Registres généraux
- Registres d'état
- SP
- PC
Pile
Tas
- Contexte du noyau
- Tables fichiers
- Structure MV
- Segment données
Données
code
4Le contexte processus Détacher le flot des
ressources
Code et données
Thread
Pile
Tas
- Contexte du thread
- Registres généraux
- Registres d'état
- SP
- PC
Données
code
- Contexte du noyau
- Tables fichiers
- Structure MV
- Segment données
5Processus multi-thread
Code et données
Thread 2
Thread 1
Pile2
Pile1
- Contexte du thread
- Registres généraux
- Registres d'état
- SP2
- PC2
- Contexte du thread
- Registres généraux
- Registres d'état
- SP1
- PC1
Tas
Données
code
- Contexte du noyau
- Tables fichiers
- Structure MV
- Segment données
6La bibliothèque des threads
- http//www.linux-kheops.com/doc/man/manfr/man-html
-0.9/man3/pthread_create.3.html
7Le man
Nom pthread_create - créé un nouveau thread
Synopsis include ltpthread.hgt int
pthread_create(pthread_t thread, pthread_attr_t
attr, void (start_routine)(void ), void
arg) Description pthread_create créé un nouveau
thread s'éxécutant concurremment avec le thread
appelant. Le nouveau thread exécute la fonction
start_routine en lui passant arg comme premier
argument. Le nouveau thread s'achève soit
explicitement en appelant pthread_exit(3) , ou
implicitement lorsque la fonction start_routine
s'achève. Ce dernier cas est équivalent à appelér
pthread_exit(3) avec la valeur renvoyée par
start_routine comme code de sortie. L'argument
attr indique les attributs du nouveau thread.
Voir pthread_attr_init(3) pour une liste complète
des attributs. L'argument attr peut être NULL,
auquel cas, les attributs par défaut sont
utilisés le thread créé est joignable (non
détaché) et utilise la politique d'ordonnancement
usuelle (pas temps-réél). Valeur Renvoyée En cas
de succès, l'identifiant du nouveau thread est
stocké à l'emplacement mémoire pointé par
l'argument thread, et 0 est renvoyé. En cas
d'erreur, un code d'errur non nul est renvoyé.
Erreurs EAGAIN pas assez de ressources système
pour créer un processus pour le nouveau thread.
EAGAIN il y a déjà plus de PTHREAD_THREADS_MAX
threads actifs. Auteur Xavier Leroy
ltXavier.Leroy_at_inria.frgt Traduction Thierry
Vignaud lttvignaud_at_mandrakesoft.comgt, 2000 Voir
Aussi pthread_exit(3) , pthread_join(3) ,
pthread_detach(3) , pthread_attr_init(3) .
8pthread.h
- ftp//sources.redhat.com/pub/pthreads-win32/dll-la
test/include/ - lien
9Création d'un thread
- Un type opaque est utilisé pour distinguer les
threads d'une application - unsigned long pthread_t (dans la bibliothèque
LinuxThreads) - Création d'un thread
- int pthread_create(
- pthread_t pThread,
- const pthread_attr_t attr,
- void (pFunction) (void),
- void pArg
- )
- Cette routine renvoie 0 si elle a réussi, sinon
elle renvoie un numéro de lerreur survenue. - pthread_create ne remplit pas la var errno.
10Le code C de thread_create
- / Thread creation /
- int pthread_create(pthread_t thread, const
pthread_attr_t attr, - void (start_routine)(void
), void arg) -
- pthread_descr self thread_self()
- struct pthread_request request
- if (__pthread_manager_request lt 0)
- if (pthread_initialize_manager() lt 0) return
EAGAIN -
- request.req_thread self
- request.req_kind REQ_CREATE
- request.req_args.create.attr attr
- request.req_args.create.fn start_routine
- request.req_args.create.arg arg
- sigprocmask(SIG_SETMASK, (const sigset_t )
NULL, - request.req_args.create.mask)
- __libc_write(__pthread_manager_request, (char
) request, sizeof(request)) - suspend(self)
11Arguments
- Le premier argument pthread_t pThread, est un
pointeur qui sera réalisé par la routine avec
l'identifiant du nouveau thread. - le second argument const pthread_attr_t attr,
correspond aux attributs dont on desire doter le
nouveau thread. Par défaut, le thread reçoit des
attributs standard. - Le troisième argument void (pFunction) (void),
est un pointeur représentant la fonction
principale du nouveau thread (c'est ce qu'il doit
faire). Dès la création du thread, la fonction
est invoquée en recevant comme argument le
pointeur passé en dernière position. Le prototype
de cette fonction est imposé et ne peut donc pas
être modifié. - Le quatrième argument void pArg est de type
void , il sera ainsi transformé dans le type de
l'argument que l'on veur passer au thread. Cet
argument est généralement un numéro permettant
d'indiquer le travail à réaliser.
12Terminaison
- La terminaison a lieu lorsque
- La fonction principale se termine.
- Par l'appel de la fonction pthread_exit
- le thread est alors éliminé
- par l'appel de pthread_exit toutes les fonctions
de nettoyage sont invoquées
13Terminaison
- Prototype de la fonction
- void pthread_exit(void pReturnValue)
14Récupération d'une valeur de retour
- Pour avoir la valeur de retour d'un thread
terminé on utilise - int pthread_join(
- pthread_t thread,
- void pPtrReturnValue
- )
- La fonction peut échouer si le thread attendu
n'existe pas s'il est détaché ou si le thread
demande sa propre fin
15Les argument de pthread_join
- L'argument pthread_t thread, est le thread qui se
termine - Le deuxième argument void pPtrReturnValue est
un pointeur sur un void utilisé pour recevoir
la valeur de retour du thread. Cette valeur de
retour est spécifiée a la fin du thread grâce a
la fonction pthread_exit. Ce dernier argument
peut être NULL si nous ne sommes pas intéressé
par la valeur de retour du thread.
16Récupération d'un entier comme code de retour
- Pour conserver la portabilité d'un programme, la
procédure a lieu en deux étapes - dans fonctionthread
- int ivalretour
- pthread_exit((void)i)
- dans le main par exemple
- void retour
- pthread_join(threadid, retour)
- Ainsi, il faut utiliser d'abord un pointeur void
temporaire, qu'on transforme ensuite en int.
17Interaction avec le thread principal
Thread Principal
Fin pthread_create()
pthread_join()
fin pthread_join()
exit()
18Synchronisation et communication de tâches
- Dans POSIX, les outils sont plus rapides et plus
puissants que les IPC - Sémaphore binaire
- Les mutex sont dédiés à l'exclusion mutuelle.
- Les attributs des mutex permettent de choisir le
protocole de gestion de ressource associé - Sémaphores en lecture/écriture
- POSIX.1c propose les sémaphore en
lecture/écriture - Aucun protocole de gestion de ressources
- Variable conditionnelle
- Utilisée avec un mutex pour créer des moniteurs
- On peut utiliser une attente bornée qui ne sera
jamais signalée. - RDV
- Après la création d'un RDV synchronisé des tâches
peuvent s'attendre mutuellement
19zones d'exclusions mutuelles
- La synchronisation est un des enjeux essentiels
du développement d'application multithreads entre
les différents fils d'exécution concurrents. - Pour accéder à des données communes, il est
indispensable de mettre en œuvre un mécanisme
d'exclusion mutuelle des threads. - Cas des mutex
- Pour créer un mutex, la librairie POSIX fournie
la fonction suivante int pthread_mutex_init( - pthread_mutex_t pMutex,
- pthread_mutexattr_t pAttributs
- )
- Pour détruire un mutex, nous utilisons la
fonction suivante int pthread_mutex_destroy(pth
read_mutex_t pMutex)
20Paramètres
- Le premier paramètre est un pointeur sur un
pthread_mutex_t destiné a recevoir le descripteur
du mutex nouvellement créé. - Le second paramètre pAttributs est utilisé pour
paramétrer le mutex, cette variable regroupe tous
les attributs du mutex, les paramètres par défaut
sont obtenus avec un pointeur Null.
21Emploi
- La fonction pthread_mutex_init est employée comme
ceci - pthread_mutex mutex
- pthread_mutexattr_t muxeattr
- /initialisationdemutexattr/
- /initialisationdumutex/
- if ((mutexmalloc (sizeof(pthread_mutex_t))Null)
- return (-1)
- pthread_mutex_init(mutex,mutexattr)
22Fonction de verrouillage et déverrouillage
- Si le mutex est libre, il peut être immédiatement
verrouillé et attribué au thread appelant. Si le
mutex est déjà maintenu par un autre thread, la
fonction reste bloquée (indéfiniment). Ce n'est
pas un point d'annulation. - int pthread_mutex_lock(pthread_mutex_t pMutex)
- Dès que le thread a fini de travailler avec les
données protégées, le mutex doit être
déverrouillé pour laisser la place a dautres
thread.Ceci est simplement réalisé en appelant
la fonction suivante - int pthread_mutex_unlock(pthread_mutex_t
pMutex)
23Attente conditionelle
- Lorsqu'un processus attend qu'un événement
survienne on emploie une technique de
synchronisation a base de variable
conditionnelle. - Un thread attend une condition il est avertit
par un autre thread lorsqu'elle est réalisée. - Lorsquun variable de condition nest plus
utilisée, il faut la libérée avec la fonction
suivante int pthread_cond_destroy(pthread_cond_t
pCond)
24Attente conditionelle
- Le principe repose sur deux fonctions de
manipulation des conditions - int pthread_cond_wait(
- pthread_cond_t pCond,
- pthread_mutex_t pMutex
- )
- int pthread_cond_signal(pthread_cond_t pCond)
- Sans oublier
- int pthread_cond_init(
- pthread_cond_t pCond,
- pthread_condattr_t pCandAttr
- )
25Scénario
- Toutes les variables de condition ont besoin
dêtre associé à un mutex spécifique qui va
bloquer le thread jusqu'à lémission de la
notification.
Thread attendant la condition Thread signalant la condition
pthread_mutex_lock
pthread_cond_wait déblocage du mutex
wait
pthread_mutex_lock
pthread_cond_signal Réveil du thread
pthread_cond_wait Tentative de récupérer le mutex
pthread_mutex_unlock
Fin de pthread_cond_wait
pthread_mutex_unlock
26Fonction d'attente temporisée
- Il faut préciser l'heure maximale et non la durée
- int pthread_cond_timewait(
- pthread_cond_t pCond,
- pthread_mutex_t pMutex,
- struct timespec expiration
- )
- pthread_cond_wait a le comportement d'un point
d'annulation. Lorsqu'un thread reçoit une demande
d'annulation durant cette fonction d'attente,
elle se termine mais doit récupérer avant le
mutex associé à la condition. Cela signifie
qu'elle peut bloquer indéfiniment avant de se
terminer.
27Annulation d'un thread
- L'annulation doit thread doit laisser les données
dans un état prévisible, et le seul état
prévisible du mutex associé à un appel
pthread_cond_wait() est le verrouillage. Bien
sur, le thread ne doit pas laisser le mutex
bloqué. On utilise une fonction de nettoyage.
28Fonction de nettoyage
- Lorsqu'un thread s'attribue une ressource qui
nécessite une libération ultérieure, il
enregistre le nom de la routine de libération
dans une pile spéciale. Lorsque le thread se
termine, les routines sont dépilées et exécutées - void pthread_cleanup_push(
- void(fonction)(void argument),
- void argument
- )
- void pthread_cleanup_pop(int execution_routine)
29Ordonnancement
- Deux niveaux de programmation concurrente sont
offert dans Posix - les processus et les threads
- L'ordonnancement peut se faire à deux niveaux
- local et global
30Ordonnancement local
1
2
n
P1
P4
P12
Le modèle d'ordonnancement est hiérarchique Les
processus sont en concurrence par priorité Le
temps alloué à P4 est réparti aux taches
Pi
31Ordonnancement global
1
2
n
T2
P1
P4
P12
Ti
Tj
T1
Les taches ou les processus sont ordonnancées au
même niveau
Pi
32Ordonnancement Mixte
1
2
n
T2
P1
P4
P12
Ti
Tj
T1
Pi
33Avantages/inconvénients
- Dans un ordonnancement local si une tâche fait
une action bloquante le processus est bloqué. - Les tâches d'un même processus ne peuvent être
ordonnancées sur un multiprocesseurs - Pour modifier dans un ordonnancement global un
paramètre influençant l'ordonnancement il faut
faire un appel système plus lourd qu'un appel de
fonction interne au processus. - Les tâches d'un même processeurs peuvent être
ordonnancées sur plusieurs processeurs
34Politique d'ordonnancement
- SCHED_FIFO
- La tâche prête (processus) qui a la plus forte
priorité au niveau global et qui est arrivée la
première - SCHED_RR
- fonctionne comme SCHED_FIFO avec un quantum de
temps appliqué par tourniquet - SCHED_OTHER
- défini par l'implémentation
- SCHED_SPORADIC
- La politique de base est la politique SCHED_FIFO,
avec une quantité de temps alloué à un serveur
dont la capacité est cette quantité
35Les attributs d'une tâche
- Les attributs d'une tâches peuvent définir
- Le type d'ordonnancement à appliquer
- La taille de la pile
- Une priorité
- La définition d'un serveur sporadique associé à
la tâche - L'état attaché ou détaché de la tâche
- Après la création d'un tâche, il est possible de
modifier les attributs d'une tâche.
36Les attributs de thread
- Création et destruction
- int pthread_attr_init ( pthread_attr_t )
- int pthread_attr_destroy (pthread_attr_t )
- Lecture
- int pthread_attr_getXXX (const pthread_attr_t ,
T) - Mise à jour
- int pthread_attr_setXXX ( pthread_attr_t , T )
XXX représente le nom de l'attribut.
37Signification et valeur de XXX
detachstate spécifie sil sera possible de se
synchroniser sur le fil dexécution une fois
quil sera terminé. PTHREAD_CREATE_JOINABLE
pour autoriser la synchronisation
PTHREAD_CREATE_DETACHED pour la
décliner. schedpolicy correspond à la politique
dordonnancement employée par le thread.
SCHED_OTHER pour lordonnancement
classique SCHED_RR pour un séquencement
temps-réel avec lalgorithme Round
Robin SCHED_FIFO pour un ordonnancement
temps-réel FIFO. Inheritsched signale si le
thread a sa propre configuration
d'ordonnancement PTHREAD_EXPLICIT_SCHED
ordonnancement spécifique au thread PTHREAD_INHE
RIT_SCHED ordonnancement hérité
38Liste complète
- int pthread_attr_setdetachstate(pthread_attr_t
attr, int detachstate) - int pthread_attr_getdetachstate(const
pthread_attr_t attr, int detachstate) - int pthread_attr_setschedpolicy(pthread_attr_t
attr, int policy) - int pthread_attr_getschedpolicy(const
pthread_attr_t attr, int policy) - int pthread_attr_setschedparam(pthread_attr_t
attr, const struct sched_param param) - int pthread_attr_getschedparam(const
pthread_attr_t attr, struct sched_param param)
- int pthread_attr_setinheritsched(pthread_attr_t
attr, int inherit) - int pthread_attr_getinheritsched(const
pthread_attr_t attr, int inherit) - int pthread_attr_setscope(pthread_attr_t attr,
int scope) - int pthread_attr_getscope(const pthread_attr_t
attr, int scope)
39Norme POSIX.1003.b
40liens
- http//old.devpaks.org/show.php?devpak18
- http//sources.redhat.com/pthreads-win32/
- http//www.humanfactor.com/pthreads/
- http//www.llnl.gov/computing/tutorials/pthreads/