chap4(2).pdf

download chap4(2).pdf

of 17

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?