Vous êtes sur la page 1sur 6

Ecole Nationale des Ingénieurs de Tunis

Filière : 2 ème année Informatique

Module: Systèmes d’exploitation

Fiche de Travaux Pratiques n° 2

Thème: Programmation Multithread

1.Objectif

Il s'agit de d’effectuer des premiers pas avec la programmation Multithread en C, en utilisant la bibliothèque pthread et d’étudier des schémas « classiques » de synchronisation.

2.Compilation

Pour utiliser la bibliothèque pthread, le code doit contenir : #include <pthread.h>

L’édition de lien doit se faire avec l'option « -pthread », c’est-à-dire pour compiler le programme « test.c » il faut taper : gcc -o test -pthread test.c

3.Manipulation des threads

Créer un thread

Pour créer un thread,on commence par déclarer une variable le représentant. Celle-ci sera de type pthread_t (unsigned long int).

Ensuite, pour créer la tâche elle-même, il suffit d'utiliser la fonction :

int pthread_create (

pthread_t * thread, // pointeur vers l'identifiant du thread

pthread_attr_t * attr, // attributs du thread, généralement NULL

void *(*start_routine) (void *), // pointeur vers la fonction à exécuter dans le thread

void *arg // argument à passer au thread

);

La fonction renvoie une valeur de type int : 0 si la création a été réussie ou une autre valeur si il y a eu une erreur.

pthread_create( thread, attribut, routine, argument ): Créer d'un thread. Le nouveau

flot d'exécution démarre en se branchant à la routine spécifiée. Cette routine reçoit

l'argument prévu.

Autres fonctions

pthread_exit( résultat ) : termine l'exécution du thread et renvoie un résultat.

pthread_join( thread, résultat ): Attendre la terminaison d'un autre thread.

pthread_kill( thread, nu_du_signal ): Envoyer un signal (UNIX) à un thread. C'est un moyen dur pour tuer un thread. Il existe des méthodes plus conviviales.

Abandonner le CPU pour le compte d'un autre thread (ou un autre

processus).

sched_yield():

4.Travail demandé

Exercice 1:

#include <stdlib.h>

#include <stdio.h>

#include <pthread.h>

void* maFonction(void* data);

int main()

{

int i;

pthread_t thread;// On cr ée un thread

pthread_create(&thread, NULL, maFonction, NULL);

for(i=0 ; i<500 ; i++)

printf("1");

printf("\n");

pthread_join(thread, NULL);

return 0;

}

void* maFonction(void* data)

{

int i;

for(i=0 ; i<500 ; i++)

printf("2");

printf("\n");

return NULL;

}

Compiler et exécuter ce code. Expliquer le résultat affiché.

Exercice 2:

#include <pthread.h>

#include <stdio.h>

void * run(void * arg)

{

 

int i;

for(i=0;i<10;i++){

printf("t1 %d \n", i);

sleep(1);

}

return NULL;

}

int main(void)

{

 

pthread_t t1;

pthread_create(&t1, NULL, run, NULL);

printf("prog principal \n");

pthread_join(t1,NULL);

printf("Fin des threads \n");

}

1. Compiler et exécuter ce code.

2. Combien de Threads sont créés suite à l'exécution de ce code.

3. Si on supprime la commande pthread_join(t1,NULL), qu'est ce qui se passe ?

4. Garder la commande pthread_join(t1,NULL), et créer un deuxième thread exécutant une fonction run2() qui fait un sleep de 2 secondes. qu'est ce qui se passe ?

Exercice 3:

Écrire un programme qui permet de créer un thread qui lit des caractères au clavier et les passe à un autre thread qui se charge de les afficher. Il faut noter que le thread principal (le père) se charge de la création de ses fils et de l'attente de leur mort. Cette disparition est programmée à l'arrivée du caractère "F".

Exercice 4:

Soit le programme suivant de calcul du nième nombre de Fibonacci :

#include <stdlib.h>

#include <stdio.h>

int fib (int n)

{

 

if (n<2) return n ;

else {

int x, y ;

x = fib (n­1) ;

y = fib (n­2) ;

return x + y ;

}

}

int main (int argc, char *argv[])

{

 

int n, res ;

n = atoi (argv[1]) ;

res = fib (n) ;

printf ("Fibo (%d) = %d\n", n, res) ;

exit (0) ;

}

1. On veut accélérer l'exécution de ce code à l'aide des threads. L'idée est d'attacher un thread à chacune des instances de la fonction fib(). On construit ainsi un arbre de threads. Avant de retourner son résultat, un thread attend que ses deux fils aient terminé.

2. On propose d'améliorer la solution précédente de la manière suivante : plutôt que de déclencher un thread alors que la valeur a déjà été produite auparavant par un autre thread, on récupère cette valeur. Pour cela, on garde les résultats intermédiaires produits dans un tableau partagé entre les threads. (Les éléments de ce tableau sont par exemple initialisés à la valeur INCONNUE pour dénoter que la valeur n'a pas encore été calculée.)

#define INCONNUE

-1 "F".