TD 2 - Thread
Exercice 1. Utilisation de pthread_create(3)
La fonction pthread_create(3) permet de créer un thread. Parmi les fragments de code ci-
dessous, un seul crée correctement un thread qui appelle la fonction f en lui passant la
chaîne de caractères s comme argument. Lequel ?
void * f( void * param) {
// incomplet
return NULL;
}
int main (int argc, char *argv[]) {
pthread_t t;
int err;
char *s;
err=pthread_create(&t,NULL,&(f),(void *) s);
}
void * f (void * param) {
// incomplet
return NULL;
}
int main (int argc, char *argv[]) {
pthread_t t;
int err;
char *s;
err=pthread_create(&t,NULL,&(f),(void *) &s);
}
void f(void * param) {
// incomplet
return NULL;
}
int main (int argc, char *argv[]) {
pthread_t *t;
int err;
char *s;
err=pthread_create(t,NULL,*f,(void *) *s);
}
Exercice 2. Passage d’arguments à un thread
Considérons un thread qui a pour objectif de convertir une fraction en un nombre en virgule
flottante. Ce n’est pas une bonne utilisation de threads puisque le calcul à effectuer est très
simple, mais cela nous permettra de voir comment un thread peut recevoir des arguments
directement. En dehors des threads, cette fonction de conversion pourrait s’écrire :
struct fraction {
int num;
int denum;
};
typedef struct fraction Fraction_t;
float tofloat(Fraction_t t) {
return (float) [Link]/ (float) [Link];
}
Parmi les programmes ci-dessous, un seul calcule correctement la valeur attendue (le test
des valeurs de retour des fonctions n’est pas présenté pour garder le code concis). Lequel ?
float mythread(Fraction_t param) {
float *r=(float *)malloc(sizeof(float));
*r=(float) param->num/ (float) param->denum;
return(r);
}
int main (int argc, char *argv[]) {
pthread_t t;
Fraction_t f;
[Link]=1;
[Link]=3;
printf("%f \n",tofloat(f));
float *r;
int err;
err=pthread_create(&t,NULL,&mythread,&(f));
err=pthread_join(t,(void *) &r);
}
void *mythread(void * param) {
Fraction_t *f=(Fraction_t *) param;
float *r=(float *)malloc(sizeof(float));
*r=(float) f->num/ (float) f->denum;
return((void *) r);
}
int main (int argc, char *argv[]) {
pthread_t t;
Fraction_t f;
[Link]=1;
[Link]=3;
float *r;
int err;
err=pthread_create(&t,NULL,&mythread,&(f));
err=pthread_join(t,(void **) &r);
}
void *mythread(void * param) {
Fraction_t f= *param;
float r;
r=(float) [Link]/ (float) [Link];
return((void *) &r);
}
int main (int argc, char *argv[]) {
pthread_t t;
Fraction_t f;
[Link]=1;
[Link]=3;
float r;
int err;
err=pthread_create(&t,NULL,&mythread,&(f));
err=pthread_join(t,(void **) &r);
}
Exercice 3
La fonction pthread_join(3) utilise un deuxième argument de type void **. Pourquoi est-il
nécessaire d’utiliser un pointeur vers un pointeur et pas simplement un pointeur void * ?
A votre avis, pourquoi le premier argument de la fonction pthread_create(3) est-il un pointeur
de type pthread_t * alors que le premier argument de la fonction pthread_join(3) est lui
simplement de type pthread_t?
Avec les threads POSIX, comment peut-on passer plusieurs arguments à la fonction
démarrée par pthread_create(3) ? Ecrivez un petit exemple en C qui permet de passer un
entier et un caractère à cette fonction.
Exercice 4
Essayez de lancer un grand nombre de threads d’exécution sur votre machine. Quel est le
nombre maximum de threads que pthread_create(3) vous autorise à lancer ?
Exercice 5
Quelle différence voyez-vous entre pthread_exit(3) et exit(3) ?
Exercice 6
Un étudiant souhaite passer un tableau d’entiers comme argument à un thread et écrit le
code suivant. Qu’en pensez-vous ?
#define SIZE 100
pthread_t mythread;
void *f(void *param) {
int *v=(int *) param;
long r=0;
for(long i=0;i<SIZE;i++) {
r+=v[i];
}
return((void *) r);
}
void launch(void ){
int v[SIZE];
for(int i=0;i<SIZE;i++) {
v[i]=1;
}
int err=pthread_create(&(mythread),NULL,&f,(void *) v);
if(err!=0)
error(err,"pthread_create");
}
int main (int argc, char *argv[]) {
launch();
// ...
return(EXIT_SUCCESS);
}
Exercice 7
Ecrivez un programme qui créé deux threads affichant chacun "Bonjour L3-S5 informatique"
Exercice 8
Ecrivez un programme ayant le comportement suivant :
• des threads sont créés (leur nombre étant passé en paramètre lors du lancement du
programme) ;
• chaque thread affiche un message (par example "hello world !" ), la valeur retounée
par pthread_self() et le pid ;
• le thread principal attend la terminaison des différents threads créés.
Exercice 9
Ecrivez un programme ayant le comportement suivant :
• des threads sont créés (leur nombre étant passé en paramètre lors du lancement du
programme) ;
• à la création de chaque thread un numéro d'ordre est passé au thread ;
• chaque thread affiche un message (par example "hello world !" ) et son numéro
d'ordre ;
• le thread principal attend la terminaison des différents threads créés.
Exercice 10
Compléter le programme ci-dessous afin que :
- le thread principal (fonction « main() ») crée deux threads ;
- le premier thread affiche « nb1 » fois une lettre donnée ;
- le deuxième thread affiche « nb2 » fois une autre lettre donnée.
Les lettres à afficher ainsi que les entiers « nb1 » et « nb1 » sont lus au clavier et passés en
argument à la fonction de thread.
# include <pthread.h>
# include <stdio.h>
struct data {
char c;
int count ;
};
void* affiche(void* k ) {
struct data *p = (struct data *)k ;
int i;
for (i = 0; i < (*p).count ; ++i)
fputc ((*p).c , stderr );
return NULL ;
}
/* Programme principal . */
int main () {