1
Threads
2
Le modèle de processus est un programme qui s’exécute selon un
chemin unique (compteur ordinal). On dit qu’il a un flot de contrôle
unique (un seul thread).
De nombreux systèmes d’exploitation modernes offrent la
possibilité d’associer à un même processus plusieurs chemins
d’exécution (multithreading, multiflots d’exécution).
Processus
Thread
3
Un thread est une subdivision d’un processus
Un flot de contrôle dans un processus
Les différents threads partagent l’espace
adressable et les ressources d’un processus
Lorsqu’un thread modifie une variable (non locale),
tous les autres threads voient la modification
Un fichier ouvert par un thread est accessible aux
autres threads(du même processus)
4
Un thread est une unité d’exécution rattachée à un
processus, chargée d’exécuter une partie du processus.
Un processus est vu comme étant un ensemble de
ressources (espace d’adressage, fichiers, périphériques…)
que ses threads (flots de contrôle ou processus légers)
partagent.
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 identifiant unique
– une pile d'exécution
– des registres (un compteur ordinal)
– un état… 5
Possède sa mémoire, ses fichiers, ses ressources,
etc.
Accès protégé à la mémoire, fichiers, ressources
d’autres processus.
6
Possède un état d’exécution (prêt, bloqué…)
Possède sa pile et un espace privé pour variables
locales
A accès à l’espace adressable, fichiers et ressources
du processus auquel il appartient en commun avec
les autres threads du même proc
7
Le multithreading permet l’exécution simultanée
ou en pseudo-parallèle de plusieurs parties d’un
même processus. 8
Réactivité (le processus peut continuer à s’exécuter
même si certaines de ses parties sont bloquées)
Ex: plusieurs threads, l’un dédié à l’interaction avec les
usagers et l’autre à traiter des données. L’un peut s’exécuter
tant que l’autre est bloqué
Partage de ressources (facilite la coopération,
améliore la performance : meilleur parallélisme),
Légèreté :Économie d’espace mémoire et de temps. Il
faut moins de temps pour :
créer, terminer un thread (sous Solaris, la création d’un processus
est 30 fois plus lente que celle d’un thread)
“switcher” entre deux threads d’un même processus.
9
La commutation entre threads est moins dispendieuse
qu’avec les processus
Un processus possède une mémoire, fichiers, et autres
ressources.
Passer d`un processus à un autre implique une
sauvegarde et restauration de l’état de ces ressources
Changer d’un thread à un autre dans le même
processus est bien plus simple car les threads
partagent le même espace d’adressage
10
Un thread pour interagir avec l’utilisateur,
Un thread pour reformater en arrière plan,
Un thread pour sauvegarder périodiquement le document
Un thread pour le contrôle de l’orthographe. 11
Le Dispatcher thread se charge
de réceptionner les requêtes.
Il choisit, pour chaque requête
reçue, un thread libre (en attente
d’une requête). Ce thread va se
charger d’interpréter la requête
12
L’implémentation du multiflot (multithreading) varie
considérablement d’une plateforme à une autre (threads
Linux, threads de Win32, threads de Solaris et threads de
POSIX).
Le multiflot peut être implémenté :
au niveau utilisateur (threads utilisateur) -> modèle
plusieurs-à-un,
au niveau noyau (threads noyau) -> modèle un-à-un,
aux deux niveaux (threads hybrides) -> modèle
plusieurs-à-plusieurs.
13
sont implantés dans une bibliothèque
(niveau utilisateur) qui fournit un support
pour les gérer.
Ils ne sont pas gérés par le noyau.
Le noyau gère les processus (table des
processus) et ne se préoccupe pas de
l’existence des threads (modèle plusieurs-
à-un).
Lorsque le noyau alloue le processeur
à un processus, le temps d’allocation du
processeur est réparti entre les différents
threads du processus (cette répartition
n’est pas gérée par le noyau).
14
Les threads utilisateur sont généralement créés, et gérés
rapidement.
efficace car les ops sur les threads ne demandent pas des
appels système
Ils facilitent la portabilité (comparativement aux autres
implémentations)
Inconvénients :
À tout instant, au plus un thread par processus est en cours d’exécution.
Cette implémentation n’est pas intéressante pour des systèmes
multiprocesseurs.
Si un thread d’un processus se bloque, tout le processus est bloqué.
Pour pallier cet inconvénient, certaines librairies transforment les appels
système bloquants en appels système non bloquants.
15
Les threads noyau sont directement supportés
par le système d’exploitation.
Le système d’exploitation se charge de leur
gestion. Un temps CPU est alloué à chaque thread.
(modèle un-à-un)
Si un thread d’un processus est bloqué, un autre
thread du processus peut être élu par le noyau
Implémentation plus intéressante pour les
systèmes multiprocesseurs.
Un processus peux ajuster les niveaux de priorité
de ses threads.
Ex: un processus peut améliorer son interactivité
en assignant :
– une forte priorité à un thread qui traite les
requêtes des utilisateurs et
– une plus faible priorité aux autres.
16
Inconvénients :
• Performance (gestion plus coûteuse)
• Les programmes utilisant les
threads noyau sont moins portables
que ceux qui utilisent des threads
utilisateur.
17
Relation entre threads utilisateur et threads noyau
plusieurs à un
un à un
plusieurs à plusieurs
Intervention sur plusieurs niveaux:
▪ Processus
▪ Thread usager
▪ Thread noyau
▪ Processeur (UCT)
18
Le SE ne connaît pas les threads utilisateur: L’utilisateur contrôle les threads
Un ensemble de threads d’un même processus peuvent être associés à un thread
noyau (pooling thread).
Inconvénient : mise en œuvre plus complexe
19
le SE contrôle les threads
Les ops sur les threads sont des appels système
Permet à un autre thread d’exécuter lorsqu’un thread
exécute un appel système bloquant
Win NT, XP, OS/2 20
Flexibilité pour l’usager d’utiliser la technique qu’il préfère
Si un thread utilisateur bloque, son kernel thread peut être affecté à un
autre
Si plus. UCT sont disponibles, plus. Kernels threads peuvent s’exécuter en
même temps
Quelques versions d’Unix, dont Solaris 21
Solaris 2 implémente le multiflot selon le modèle plusieurs-à-plusieurs.
Il distingue 3 niveaux de threads :
– threads utilisateur,
– processus poids léger (LWP) et
– threads noyau.
Fonctionnent comme des UCT virtuelles, pouvant exécuter des threads niveau usager
Sont entre les threads usager et les threads noyau
Il y a un thread noyau pour chaque LWP, chaque LWP est lié à son propre thread noyau
Chaque processus doit contenir au moins un LWP
La bibliothèque des threads exécute les threads utilisateur sur les LWP disponibles
Seulement les threads qui sont associés à un LWP peuvent exécuter, les autres sont en
attente d’exécution (bloqués) 22
23
Un thread à niveau usager est lié s’il est attaché à
un LWP de façon permanente
Est non lié sinon
24
Les LWP sont demandés quand un thread usager a
besoin de communiquer avec le noyau
Appel système (E/S, accès disque…)
Dans ce cas un nouveau thread peut s’exécuter tant que
l’autre est bloqué en attente
Il y a besoin d’un LWP pour chaque thread qui
devient bloqué pour un appel système
Ex : s’il y a 5 threads qui demandent des E/S, nous avons
besoin de 5 LWP
s`il y a 4 LWP disponibles, une des demandes d’E/S doit
attendre qu’un LWP devienne libre ou soit créé
25
Les threads noyau qui implémentent les LWP exécutent
sur les UCT qui deviennent disponibles
Si un thread noyau se bloque, son LWP se bloque aussi,
mais un processus (tâche) peut en obtenir un autre, ou un
nouveau LWP peut être créé
Si un LWP devient bloqué,
l’UCT qui l’exécute peut être
affectée à un autre thread
26
La biblio. de threads à niveau usager crée
automatiquement des nouveaux LWP au besoin
Termine les LWP qui ne sont plus demandés
27
Une tâche=processus Solaris peut être associée à plusieurs
LWP
Un LWP contient un ensemble de registres, des infos de
mémoire et de comptabilisation
Les structures des données sont essentiellement des PCBs
enchaînés
28
L’objectif premier des Pthreads est la portabilité
(disponibles sous Solaris, Linux, Windows XP… ).
#include <pthread.h>
29
int pthread_create(pthread_t *tid, //récupérer le TID du thread créé
const pthread_attr_t *attr, //préciser les attributs du thread (taille de la pile,
//priorité….), attr = NULL par défaut
void * (*func) (void*), // est la fonction à exécuter par le thread
void *arg); //le paramètre de la fonction.
L'appel renvoie 0 s'il réussit, sinon il renvoie une
valeur non nulle identifiant l'erreur qui s'est produite
30
void pthread_join( pthread_t tid, void **status);
Attend la fin d’un thread. L’équivalent de waitpid
des processus sauf qu’on doit spécifier le tid du
thread à attendre.
status sert à récupérer la valeur de retour et l’état
de terminaison.
pthread_t pthread_self(void);
Retourne le TID du thread.
31
void pthread_exit( void * status);
Termine l'exécution du thread
Si le thread n’est pas détaché, le TID du thread et l’état de terminaison
sont sauvegardés pour les communiquer au thread qui effectuera
pthread_join.
Un thread détaché (par la fonction pthread_detach(pthread_t tid)) a pour
effet de le rendre indépendant de celui qui l'a créé (plus de valeur de retour
attendue).
Un thread peut annuler ou terminer l’exécution d’un autre thread
(pthread_cancel). Cependant, les ressources utilisées (fichiers, allocations
dynamiques, verrous, etc) ne sont pas libérées.
Il est possible de spécifier une ou plusieurs fonctions de nettoyage à
exécuter à la terminaison du thread (pthread_cleanup_push() et
pthread_cleanup_pop()).
32
Ecrire un programme qui réera un thread qui
affichera son PID, mais le programme principal ne
fera rien d'autre que tourner en boucle. Les deux
threads (principal et fils) continueront à s'exécuter
indéfiniment
▪ Terminez l’execution du programme.
33
34
Ecrire un programme dans lequel le thread
principal crée deux threads A et B et attend la fin
de leurs exécutions.
Un de ces threads crée lui-même un thread C qu’il
attendra avant de terminer
35
36
37
38
39
Ecrire un programme qui simule des opérations de
modification sur une variable partagée entre deux
threads.
La variable s'appelle glob et est initialisée à 0.
Le premier thread doit ajouter 2 à glob
Le second thread doit soustraire 1 de glob.
Le programme doit afficher la valeur de glob après
chaque modification et le PID du processus principal.
40
41
42
Écrire un programme qui crée un thread pour
modifier une variable globale "message’’, initialisée
à "Hola mundo". Le thread doit afficher ce
message, attendre 5 secondes, puis le changer en
"Adios !".
Le programme attend la fin du thread et affiche le
message modifié ainsi que le message de
terminaison du thread.
43
44
45
Les threads sont utilisés pour le traitement parallèle de
l'information.
Ex 1: Serveur de fichiers: Création d’un Thread à chaque
requête et envoie des résultats au client après traitement.
Ex 2: Calcul matriciel et vectoriel. La multiplication de
deux matrices a et b de m colonnes=n lignes=3 peut être
parallélisée.
46
Ecrire un programme qui montre l'utilisation des
vecteurs de threads pour faire la somme de deux
matrices A et B de N éléments.
La somme de chaque ligne est calculée avec des
threads indépendants en parallèle. Les
composantes sont générées aléatoirement avec
srand().
47
vecteurs de threads pour
faire la somme de deux
matrices A et B de NxN
éléments
48
*
49