Université Pierre et Marie Curie Master 2016 2017
PR : Travaux Dirigés 4. Introduction aux processus légers

Cette séance consiste à mettre en pratique la notion de processus léger, en particulier pour comprendre les phénomènes de concurrence induits, et les gérer par les mécanismes de synchronisation qui leur sont propres. On utilisera pour cela la bibliothèque pthreads à inclure par pthread.h, et non les sémaphores anonymes. On trouvera en annexe un Makefile permettant de gérer ses fichiers conformément aux spécifications données lors de la première séance. Selon les systèmes, il faudra parfois l’utiliser ainsi :

LDFLAGS=’-lpthread’ make but

ou le modifier pour donner systématiquement cette valeur à LDFLAGS.

Par ailleurs, les fonctions sur les processus légers, en cas d’erreur, n’affectent pas la globale errno (car elle peut être modifiée à tout moment par un autre processus léger) : on signalera donc les erreurs non avec perror et errno, mais en écrivant sur le flux des erreurs le résultat des dites fonctions quand il est non nul.



1 Création de threads

Ecrire un programme prenant en argument un nombre N et créant N processus légers (à l’aide de pthread_create) et passant en paramètre à chacune son numéro de création compris entre 0 et N. Chacune affichera son numéro de création et son identité (utiliser pthread_self). Ensuite elle se termine, avec pthread_exit, en retournant son numéro de création multiplié par 2. De son côté, le programme principal doit attendre leur terminaison (à l’aide de pthread_join) en affichant la valeur renvoyée par chaque.

Exemple d'appel :
$PWD/bin/thread_create 10
Fichier à créer : src/thread_create.c

2 Exclusion mutuelle de threads

Modifier le programme de l’exercice précédent pour que chaque thread, au lieu d’afficher son numéro de création, calcule une valeur aléatoire entre 0 et 10 à l’aide de la fonction rand de la façon suivante :

(int) (10*((double)rand())/ RAND_MAX)

Cette valeur aléatoire sera affichée, puis ajoutée à une variable globale, initialisée à zéro par le programme principal. On veillera évidemment à éviter les accès concurrents à cette variable, en utilisant les fonctions de la famille pthread_mutex_lock. Après terminaison de toutes les threads, le programme affiche la valeur finale de cette variable.

Exemple d'appel :
$PWD/bin/thread_rand 10
Fichier à créer : src/thread_rand.c

3 Réveil de threads

Modifier le programme précédent pour que la valeur finale soit affichée non plus par le programme principal mais par une nouvelle thread créée au départ. Celle-ci, après sa création, doit se bloquer en attendant que la somme de toutes les valeurs aléatoires soit complétée. La dernière thread à ajouter sa valeur aléatoire utilisera pthread_cond_signal pour signifier à la première qu’elle peut afficher la valeur de la globale. On utilisera une variable statique dans la fonction appelée à la création de la thread pour compter le nombre de ses appels, et repérer ainsi le dernier appel (le problème peut se résoudre sans d’autres variables globales que celle additionnant les valeurs aléatoires).

Exemple d'appel :
$PWD/bin/thread_wait 10
Fichier à créer : src/thread_wait.c

4 Annexes


makefile
Format de l'envoi : src/thread_create.c
Répertoires autorisés : src/thread_rand.c src/thread_wait.c