chap4(2).pdf
-
Upload
daha-ahmed -
Category
Documents
-
view
215 -
download
0
Transcript of chap4(2).pdf
-
7/25/2019 chap4(2).pdf
1/17
Chapitre 4
Les threads
4.1 Introduction
Le modle de processus dcrit au chapitre prcdent est un programmequi sexcute selon un chemin unique avec un seul compteur ordinal. Ondit quil a unflot de contrle uniqueou un seulthread. De nombreux sys-tmes dexploitation modernes offrent la possibilit dassocier un mmeprocessus plusieurs chemins dexcution ou multithread (figure 4.1). Ilspermettent ainsi lexcution simultane des parties dun mme processus.Chaque partie correspond un chemin dexcution du processus. Le pro-cessus est vu comme tant un ensemble de ressources (code excutable,segments de donnes, de fichiers, de priphriques, etc.) que ces parties ap-peles flots de contrle ou processus lgers (threadsen anglais) partagent.Chaque flot de contrle (thread) a cependant, en plus des ressources com-munes, sa propre zone de donnes ou de variables locales, sa propre pile
dexcution, ses propres registres et son propre compteur ordinal.
4.1.1 Avantages
Comparativement aux processus un flot de contrle unique, un threadou processus lger avec plusieurs flots de contrle prsente plusieurs avan-tages, notamment :
Ractivit. Le processus lger continue sexcuter mme si certainesde ses parties sont bloques.
Partage de ressources. conomie despace mmoire et de temps. Par exemple sous Solaris,
la cration dun processus est 30 fois plus lente que celle dun proces-
1
-
7/25/2019 chap4(2).pdf
2/17
2 CHAPITRE 4. LES THREADS
un processus
un thread
un processus
multiples threads
multiples processus
un thread par processus
multiples processus
multiples threads par processus
FIG . 4.1 Threads vs. processus.
sus thread.
4.1.2 Threads utilisateur et noyau
La majorit des systmes permettent lemultiflot(multithreading). Ilssont offerts soit au niveau utilisateur, soit au niveau noyau (voir le Chapitre??Ordonnancement des processus, pour les dtails sur lordonnancementdes threads et des processus).
Les threads utilisateur sont supports au-dessus du noyau et sont implan-ts par unebibliothque de threads au niveau utilisateur (par exemplepthreadsous Linux ou thread dans Solaris). Ils sont portables surdiffrentes plate-formes. Ils sont grs par une application o le blo-cage du thread peut bloquer le processus complet. Le changement decontexte est rapide.
Les threads noyau sont directement supports par le noyau du systmedexploitation. Le systme dexploitation se charge de leur gestion etle changement de contexte est lent.
Les threads combins sont implants par le systme dexploitation (utili-
sateur et systme). Les threads utilisateur sont associs des threads
-
7/25/2019 chap4(2).pdf
3/17
4.2. SERVICESPOSIXDE GESTION DE THREADS 3
systme. La plupart des tches gestion seffectuent sous le mode uti-lisateur.
Les oprations concernant les threads sont notamment la cration, la termi-naison, la suspension et la relance.
4.2 ServicesPosixde gestion de threads
Linux ne fait pas de distinction entre les processus et les threads. Unthread est un processus qui partage un certain nombre de ressources avecle processus crateur : lespace dadressage, les fichiers ouverts ou autres.Pour la gestionPosixde threads, Linux utilise la bibliothque pthread,qui doit tre appele par lditeur de liens.
Cration de threads
int pthread_create (pthread_t *thread ,
pthread_attr_t *attr,void *nomfonction,
void *arg );
Le service pthread_create() cre un processus lger qui excute la fonc-tion nomfonction avec largument arg et les attributs attr. Les attributspermettent de spcifier la taille de la pile, la priorit, la politique de plani-fication, etc. Il y a plusieurs formes de modification des attributs.
Suspension de threads
int pthread_join(pthread_t *thid, void **valeur_de_retour);
pthread_join()suspend lexcution dun processus lger jusqu ce quetermine le processus lger avec lidentificateur thid. Il retourne ltat determinaison du processus lger.
Terminaison de threads
void pthread_exit(void *valeur_de_retour);
pthread_exit()permet un processus lger de terminer son excution,en retournant ltat de terminaison.
int pthread_attr_setdetachstate(pthread_attr_t *attr,
int detachstate);
-
7/25/2019 chap4(2).pdf
4/17
4 CHAPITRE 4. LES THREADS
pthread_attr_setdetachstate() sert tablir ltat de terminaisondun processus lger :
Si detachstate = PTHREAD_CREATE_DETACHED le processus l-ger librera ses ressources quand il terminera.
Si detachstate = PTHREAD_CREATE_JOINABLE le processus l-
ger ne librera pas ses ressources. Il sera donc ncessaire dappelerphtread_join().
Exemple 1. Le programme thread-pid.cmontre limplantation dethreads dans GNU/Linux, ainsi que la rcupration dupid du thread.
Listing 4.1 thread-pid.c
# i nc l ud e < u ni s td . h > / / pour s l ee p# i n c lu d e < p th re ad . h > / / p th r e a d _ cr e a t e , p t h r ea d _ j o i n , p t h r ea d _ e x i t# i n c l u d e < s t d i o . h >
void f o n c t i o n (void
arg )
{
p r i n t f ( " p i d du t h r e ad f i l s = % d\n " , ( i n t) getpid ( ) ) ;
while ( 1 ) ; / / f o r e ve r10 re turn NULL;
}
int main (){
p t hr e a d_ t t hr e a d ;
p r i nt f ( " p i d de mai n = %d\n" , ( i n t) getpid ( ) ) ;pthr ead _cr eate (&thread , NULL, & fo nc tio n , NULL) ;while ( 1 ) ; / / f o r e v e r
20
return 0 ;}
tant donn que aussi bien main() que la fonction_thread()tournenttout le temps, cela nous permet de regarder de prs des dtails de leurexcution. Le programme doit tre compil avec la librairie -lpthreadLexcution en tche de fond de pthread-pid.c est :
leibnitz> gcc -o pthread-pid thread-pid.c -lpthread
leibnitz> pthread-pid &
[1] 24133
leibnitz> pid de main = 24133
pid du thread fils = 24136
-
7/25/2019 chap4(2).pdf
5/17
4.2. SERVICESPOSIXDE GESTION DE THREADS 5
leibnitz> ps x
PID TTY STAT TIME COMMAND
23928 pts/2 S 0:00 -tcsh
24133 pts/2 R 0:53 pthread-pid
24135 pts/2 S 0:00 pthread-pid
24136 pts/2 R 0:53 pthread-pid
24194 pts/2 R 0:00 ps x
Le pid 24133correspond au processus de main(),24136est le PID dufonction_thread() elle mme, mais qui est le processus 24135qui en plus dort ? Dun autre cot, la seule faon de terminer lexcution duprogramme prcdent, cest lutilisation de la commande kill, avec le pidcorrespondant :
leibnitz> kill 24133
leibnitz> [1] Terminated pthread-pid
FIG . 4.2 Exemple de synchronisation de threads.
Exemple 2.La figure 4.2 illustre un exemple de cration de threads. Lethread principal cre deux threads A et B et attend la fin de leurs excu-
tions. Un de ces threads cre lui-mme un thread C qul attendra avant de
-
7/25/2019 chap4(2).pdf
6/17
6 CHAPITRE 4. LES THREADS
terminer. Le listing exemple-threads.c montre une implmentation decet exemple.
Listing 4.2 exemple-threads.c
#define _REENTRANT
#include < p t hr e ad . h>#include < unistd . h>#include < s t d i o .h>
void a f f i c h e r ( i n t n , char l e t t r e ){
10 i n t i , j ;
for ( j = 1 ; j
-
7/25/2019 chap4(2).pdf
7/17
4.2. SERVICESPOSIXDE GESTION DE THREADS 7
{p t hr e a d_ t t hC ;pth re ad _c re ate (&thC , NULL, threadC , NULL) ;
50 a f f ic h e r ( 1 0 0 , B ) ;
p r i n t f ( " \n L e t h re a d B a t te n d l a f i n du t h re a d C\n " ) ;pth re ad _j oi n ( thC ,NULL) ;p r i nt f ( " \ n F i n du t hr e a d B\n" ) ;f f l u s h ( s t do u t ) ;
pth re ad _ex it (NULL) ;}
60int main (){
int i ;p t hr e a d_ t thA , t hB ;
p r i nt f ( " C r e a t i o n du t hr e a d A " ) ;pth re ad _c re ate (&thA , NULL, threadA , NULL) ;pth re ad _c re ate (&thB , NULL, threa dB , NULL) ;sle ep ( 1) ;
70
// a t te n d r e que l e s t h re a ds a i e n t t er m in e
p r i n t f ( " L e t h re a d p r i n c i p a l a t te n d que l e s a u t r es s e t e rm i n en t \n " ) ;
pth re ad _j oi n ( thA ,NULL) ;pthread_join ( thB ,NULL) ;
80e x i t ( 0 ) ;
}
Exemple 3.Le programme threads.cppmontre lutilisation des va-riables globales, ainsi que le passage de paramtres lors des appels de thre-ads.
Listing 4.3 threads.cpp
#include < u ni std . h > // sl ee p
#include < p th r ea d . h > // p t h re a d _ c re a t e , p t h r ea d _ j o i n , p t h r ea d _ e x i t
-
7/25/2019 chap4(2).pdf
8/17
8 CHAPITRE 4. LES THREADS
#include < s t d i o .h>
in t g l o b = 0 ;void
increment (void
) ; void
decrement (void
) ;
in t main ()
{10 p thr ea d _ t t i d 1 , t i d 2 ;
pr in tf ( " i c i main[%d ] , glob = %d\n" , getpid ( ) , glob ) ;
/ / c r a t i o n d u n t h r e ad p ou r i n c r e m en ti f ( p t hr e a d _ cr e a t e ( & t i d1 , NULL, i ncr e me nt , NULL) ! = 0 )
return 1 ;p r i n t f ( " i c i main : c r e a t i o n du t h re a d[%d ] a ve c s uc c s \n " , t i d 1 ) ;
/ / c r a t i o n d u n t h r e ad p ou r d ec re me nti f ( pthr ead _cr eate (&ti d2 , NULL, decrement , NULL) ! = 0 )
20 re turn
1 ;p r i n t f ( " i c i main : c r e a t i o n du t h re a d [% d ] a ve c s uc c s \n " , t i d 2 ) ;
/ / a t te n d re l a f i n d es t hr ea d spth re ad _j oi n ( ti d1 , NULL) ;pth re ad _j oi n ( ti d2 , NULL) ;p r i n t f ( " i c i main : f i n d es t h r e a d s , g l o b = % d \ n " , g l o b ) ;
return 0 ;}
30 void decrement (void
)
{int de c= 1 ;s l e e p ( 1 ) ;g l o b = g l o b
d ec ;
p r i nt f ( " i c i de cr e me nt [%d ] , g l o b = % d\n" , p t hr e a d _ s e l f ( ) , g l o b ) ;pth re ad _e xi t (NULL) ;
}
void i n c re m en t ( void
)
40 {int inc =2;s l e e p ( 1 0 ) ;g l o b= g l ob + i n c ;p r i nt f ( " i c i i ncr e me nt [%d ] , g l o b = % d\n" , p t hr e a d _ s e l f ( ) , g l o b ) ;pth re ad _e xi t (NULL) ;
}
Rsultat du programme threads.cpp :
leibnitz> gcc -o pthread threads.cpp -lpthread
-
7/25/2019 chap4(2).pdf
9/17
4.2. SERVICESPOSIXDE GESTION DE THREADS 9
leibnitz> pthread
ici main[21939], glob = 0
ici main : creation du thread[1026] avec succs
ici main : creation du thread [2051] avec succs
ici increment[21941], glob = 2
ici decrement[21942], glob = 1
ici main : fin des threads, glob = 1
leibnitz>
Le programme thread-param.csuivant illustre le passage de para-mtres entre threads.
Exemple 4.Passage de paramtres.
Listing 4.4 thread-param.c
#include < s t d i o .h>#include < unistd . h>#include < s t d l i b . h >
#include < pthrea d . h>
void
t hr e a d _ f u nct i o n (void
arg ) ;char message [ ] = " Hola mundo" ;
int main ()10 {
int r e s ;p t hr e a d_ t a _ t hr e a d ;void
t h r e a d _ r e s u l t ;
r e s = p t hr e a d _ cr e a t e (& a _ t hr e a d , NULL, t hr e a d _ f u nct i o n ,(void
) message ) ;
i f ( r es ! = 0 )
{p e r r o r ( " T hr ea d c r e a t i o n f a i l e d " ) ;
20 e x i t ( EXIT_FAILURE ) ;}
p r i n t f ( " En a t t e n t e qu e l e t h r e ad t e rm i n e . . . \ n " ) ;r e s = p t h r e a d _ j o i n ( a _ t h r ea d , & t h r e a d _ r e s u l t ) ;i f ( r es ! = 0 ){
p e r r o r ( " Echec dans l u nio n du t hr e a d " ) ;e x i t ( EXIT_FAILURE) ;
}30 p r in tf ( " Thread ter mine % s\n " , ( char
) t h r e a d _ r e s u l t ) ;
pr in tf ( "Le message es t %s\n" , message ) ;
exit (EXIT_SUCCESS) ;
-
7/25/2019 chap4(2).pdf
10/17
10 CHAPITRE 4. LES THREADS
}
void t h r e a d _ f u n c t i o n (void
arg )
{p r i n t f ( " L a f o n c t i o n du t h r e a d d em ar re . L a rg um en t e s t % s \ n " ,
(char ) a r g ) ;
s l e e p ( 5 ) ;40 s tr cp y ( message , " Adios ! " ) ;
p t hr e a d _ e x i t ( " M e r ci p a r l e t emps de CPU " ) ;}
Rsultat du programme thread-param.c :
leibnitz> gcc -o thread-param thread-param.c -lpthread
leibnitz> thread-param
leibnitz> Le thread demarre. Largument est Hola mundo
En attente que le thread termine...
Thread termin Merci pour le temps de lUCT
Le message est Adios!
leibnitz>
Algorithmes vectoriels
Il y a plusieurs exemples dutilisation des threads pour le traitementparallle de linformation. Unserveur de fichiers1 par exemple, ncessitela gestion et la manipulation de plusieurs requtes en mme temps, quipeuvent tre effectues par lutilisation des threads. Ainsi, la cration dunethread chaque requte est envisageable : les threads effectuent les traite-ments ncessaires et envoient les rsultats au client.
La manipulation des matrices et des vecteurs est un autre champ par-
ticulirement propice pour les algorithmes parallles. La multiplication dedeux matricesaetbde
colonnes =
lignes = 3, par exemple, peut treparalllis, puisque :
1Le modle client-serveur sera tudi au Chapitre ?? Introduction aux systmes distri-
bus.
-
7/25/2019 chap4(2).pdf
11/17
4.2. SERVICESPOSIXDE GESTION DE THREADS 11
Ainsi, chaque lment de la matrice rsultat peut tre un thread. Onaura donc 9 thread dans cet exemple.
Exemple 5.Le programme suma-mat.cci-dessous illustre lutilisation des vec-
teurs de threads pour faire la somme de deux matrices A et B de N lments.La somme de chaque ligne est calcule avec des threads indpendants enparallle. Les composantes sont gnres alatoirement avecsrand().
Listing 4.5 suma-mat.c
# i ncl u d e < p t hr e ad .h># i n c l u d e < s t d i o . h ># i n c l u d e < s t d l i b . h ># i n c l u d e < t i m e . h ># d e f i n e N 4 // T a i l l e des m a t r i c e s# d e f i n e M 1 0 // Nb Maximum
void s o mme _ ve ct o r i e l l e (void a r g ) ; / / Somme de s m a t r i c e s
void imprime( i n t mat ric e [N][N] ) ;10 p thr e ad _ t t i d [N ] ; // V e cte u r s t hr e a d s
int A[N] [N ] , B [N] [N ] ; // M a tr i ce sint C[N] [N ] ; // C=A+Bint f i l a ; // La f i l e des 2 m a t r i c e s
int main(void ){int j , k , s e m i l la ;/ / G e ne r a ti o n d es m a t r i c e sse mi ll a = t ime (NULL) ;
20 s ra nd ( s e m i l l a ) ;for ( j = 0 ; j< =N
1 ; j + +)
for(k =0 ; k
-
7/25/2019 chap4(2).pdf
12/17
12 CHAPITRE 4. LES THREADS
imprime(A ) ;pr in tf ( "\n\nMatrice B" ) ;
40 i mp ri me ( B ) ;pr in tf ( "\n\n Matri z C=A+B" ) ;imprime(C ) ;
return 0 ;
}
void imprime( i n t matric e [N] [N]){int j , k ;for ( j = 0 ; j< =N
1 ; j + +)
50 {pr in tf ( "\n" ) ;for(k =0 ; k
-
7/25/2019 chap4(2).pdf
13/17
4.2. SERVICESPOSIXDE GESTION DE THREADS 13
6 6 0 9
5 5 7 7
2 7 0 6
4 1 6 5
Matrice B
0 3 9 7
9 3 5 6
6 8 6 4
4 8 2 3
Matriz C=A+B
6 9 9 16
14 8 12 13
8 15 6 10
8 9 8 8 leibnitz>
Exemple 6.Le programme threads.cppmontre lutilisation des va-riables globales et le passage de paramtres.
Listing 4.6 threads.cpp
#include < u ni std . h > // sl ee p#include < p th r ea d . h > // p t h re a d _ c re a t e , p t h r ea d _ j o i n , p t h r ea d _ e x i t#include < s t d i o .h>
int g l o b = 0 ;void
increment (void
) ; void
decrement (void
) ;
int main (){
10 p thr ea d _ t t i d 1 , t i d 2 ;pr in tf ( " i c i main[%d ] , glob = %d\n" , getpid ( ) , glob ) ;
/ / c r a t i o n d un t h r e ad p ou r i n c r e m en ti f ( p t hr e a d _ cr e a t e ( & t i d1 , NULL, i ncr e me nt , NULL) ! = 0 )
return 1 ;p r i n t f ( " i c i main : c r e a t i o n du t h re a d[%d ] a ve c s uc c s \n " , t i d 1 ) ;
/ / c r a t i o n d un t h r e ad p ou r d ec re me nti f ( pthr ead _cr eate (&ti d2 , NULL, decrement , NULL) ! = 0 )
20 re turn 1 ;
p r i n t f ( " i c i main : c r e a t i o n du t h re a d [% d ] a ve c s uc c s \n " , t i d 2 ) ;
/ / a tt e nd r e l a f i n d es t hr ea d s
pth re ad _j oi n ( ti d1 ,NULL) ;
-
7/25/2019 chap4(2).pdf
14/17
14 CHAPITRE 4. LES THREADS
pth re ad _j oi n ( ti d2 , NULL) ;p r i n t f ( " i c i main : f i n d es t h r e a d s , g l o b = % d \ n " , g l o b ) ;
return 0 ;}
30 void decrement (void )
{int de c= 1 ;s l e e p ( 1 ) ;g l o b = g l o b
d ec ;
p r i nt f ( " i c i de cr e me nt [%d ] , g l o b = % d\n" , p t hr e a d _ s e l f ( ) , g l o b ) ;pth re ad _e xi t (NULL) ;
}
void i n c re m en t ( void )40 {
int inc =2;s l e e p ( 1 0 ) ;g l o b= g l ob + i n c ;p r i nt f ( " i c i i ncr e me nt [%d ] , g l o b = % d\n" , p t hr e a d _ s e l f ( ) , g l o b ) ;
pth re ad _e xi t (NULL) ;}
Trois excutions du programme threads.cpp, sur la machine Unix ju-piter :
jupiter% gcc -o threads threads.cpp -lthread
jupiter% threads
ici main[18745], glob = 0
ici increment[18745], glob = 2
ici decrement[18745], glob = 1
ici main, fin des threads, glob = 1
jupiter% threadsici main[18751], glob = 0
ici decrement[18751], glob = -1
ici increment[18751], glob = 1
ici main, fin des threads, glob = 1
jupiter% threads
ici main[18760], glob = 0
ici increment[18760], glob = 1
ici decrement[18760], glob = 1
ici main, fin des threads, glob = 1
Exemple 7.
-
7/25/2019 chap4(2).pdf
15/17
4.2. SERVICESPOSIXDE GESTION DE THREADS 15
Le programmethreads2.cpp effectue le passage de paramtres unthread :
Listing 4.7 threads2.cpp
# i ncl u d e < u ni s t d .h > / /p ou r s l e e p
# i n c l ud e < t h re a d . h > / / t h r _ c r e a t e e t t h r _ j o i n# i n c l u d e < s t d i o . h >
int g l o b = 0 ;void
increment (void
in c ) ;
void
decrement (void
dec ) ;
int main ()10 {
in t i nc = 2 , dec = 1 ;pr in tf ( " i c i main[%d ] , glob = %d\n" , getpid ( ) , glob ) ;th r_ cr ea te (NULL, 0 , increment , & inc , 0 ,NULL) ;th r_ cr ea te (NULL, 0 , decrement , & dec , 0 ,NULL) ;while (( thr_join (NULL,NULL,NULL)==0));
p r i n t f ( " i c i main , f i n d es t h r e a ds , g l o b = %d \ n " , g l o b ) ;return 0 ;
}
20 void decrement (void de c){
in t locd = ( i n t
) de c ;
s l e e p ( 1 ) ;glob
= l o cd ;
pr in tf ( " i c i decrement[%d ] , glob = %d\n" , getpid ( ) , glob ) ;return ( NULL) ;
}
void i n c re m en t ( void
inc )
30 {in t l o c i =
( i n t
) i n c ;
s l e e p ( 1 ) ;g lo b + = l o c i ;p r i n t f ( " i c i i ncr e me nt[%d ] , g l o b = % d\n" , g e t p i d ( ) , g l o b ) ;return ( NULL) ;
}
Excution programmethreads2.cpp :
jupiter% gcc threads2.cpp -lthread
jupiter% a.out
ici main[19451], glob = 0
ici decrement[19451], glob = 1
-
7/25/2019 chap4(2).pdf
16/17
16 CHAPITRE 4. LES THREADS
ici increment[19451], glob = 2
ici main, fin des threads, glob = 1
-
7/25/2019 chap4(2).pdf
17/17
4.3. EXERCICES 17
4.3 Exercices
1. On sait quun thread est cr par un processus parent, mais quellediffrence existe-il entre un thread et un processus fils ?
2. Quelle serait un avantage principal utiliser des threads plutt que
des processus fils?