diff --git a/README.md b/README.md index 1114b06..9cee99c 100644 --- a/README.md +++ b/README.md @@ -34,5 +34,8 @@ Rappels sur la gestion de la [mémoire](cours/memoire.pdf), [td1](td/td1/td1.pdf ### Semaine 5 (29/09 - 03/10) [Tubes, redirections](cours/pipe.pdf), [td5](td/td5/td5.pdf), [tp5](tp/tp5). +#### Semaine 6 (06/10 - 10/10) +[API threads posix](cours/thread.pdf), [tp6](tp/tp6). + diff --git a/tp/tp6/README.md b/tp/tp6/README.md new file mode 100644 index 0000000..3ec9f67 --- /dev/null +++ b/tp/tp6/README.md @@ -0,0 +1,160 @@ +# TP : Threads + +#### Ex1 +```c +#include +#include +#include +#include + +#define NUM_THREADS 16 + +void *thread(void *thread_id) { + int id = *((int *) thread_id); + printf("Hello from thread %d\n", id); + + return NULL; +} + +int main() { + pthread_t threads[NUM_THREADS]; + for (int i = 0; i < NUM_THREADS; i++) + assert( pthread_create(&threads[i], NULL, thread, &i) == 0); + + for (int i = 0; i < NUM_THREADS; i++) + assert( pthread_join(threads[i], NULL) == 0); + + return EXIT_SUCCESS; +} +``` + +1. Est-ce que l’exécution de ce programme est correcte? Vous pouvez vous en assurer en l’exécutant plusieurs fois. +2. Si vous pensez (et avez constaté) que ce n’est pas le cas, expliquez pourquoi. +3. Modifiez le code pour qu’il donne le résultat attendu. + + +#### Ex2 +On veut écrire un programme calculant la somme des entiers +de `1` à `N` à l’aide de `M` threads. Chaque thread calculera la somme +d’un sous-ensemble de ces entiers et la somme globale sera obtenue en +calculant la somme des résultats intermédiaires de chaque thread. + +Les entiers sont répartis uniformément entre les threads comme suit (exemple avec 3 threads) : + +Thread 1 : 1, 4, 7, ... +Thread 2 : 2, 5, 8, ... +Thread 3 : 3, 6, 9, ... + + +Le programme doit lancer `M` threads, attendre qu’ils se terminent, faire la somme des résultats +intermédiaires et afficher le résultat. Les valeurs `N` et `M` seront passées en ligne de commande. + +Il est important que le programme respecte les points suivants : + +- L’implémentation ne doit utiliser aucune variable globale. +- Le travail à effectuer pour chaque thread créé doit être aussi équitable que possible, quelles + que soient les valeurs `N` et `M` choisies par l’utilisateur (ex : N=20, M=8). +- Évitez d’utiliser un tableau pour contenir les valeurs à additionner. +- Réaliser un test de validation automatiquement du résultat obtenu (vous devez connaître le résultat !). + + +Comparez le temps d'éxecution en fonction du nombre de threads. + + + +```c +/* pour "mesurer" le temps */ +static inline double tstamp(void) +{ + struct timespec tv; + clock_gettime(CLOCK_MONOTONIC, &tv); + return tv.tv_sec + tv.tv_nsec * 1.0e-9; +} +``` +#### Ex22 +On reprend l'exercice d'un tp précédent qui calcule une approximation du nombre pi en simulant des lancers de flechettes +sur un disque. + +Un lancer consiste à tirer aléatoirement la position `(x,y)` de la flechette dans le quart supérieur droit du disque `[0,1]x[0,1]`. +On comptabilise le nombre de lancers à l'intérieur du disque (`x^2+y^2 <= 1`). + +Paralléliser le [code](src/pi.c) en créant pour la simulation plusieurs threads (passé à la ligne de commande). + +Remarque : dans le code fournit, on utilise la fonction `rand_r`, et pas `rand`. Cette dernière n'est pas réentrante (état global caché). + +#### Ex3 +On souhaite écrire une petite librairie implantant une pile d'entiers. Sa taille sera statique, et determinée au moment +de sa création. Voici l'interface : + +```c +stack_t * stack_create(int max_size); +``` +crée une pile de taille `max_size` + +```c +int stack_destroy(stack_t *s); +``` + +détruit la pile + +```c +int stack_push(stack_t *s, int val); +``` + +empile la valeur `val` renvoie 1 en cas de succès, 0 sinon. + +```c +int stack_pop(stack_t *s,int *val); +``` + +dépile dans `*val`. renvoie 1 en cas de succès, 0 sinon. + + +( Décider ce que contiendra la structure stack_t définissant un objet de type pile et penser à insérer des assertions dans le code aux endroits nécessaires.) + +1. Testez votre implantation avec une utilisation monothreadé. +2. Testez votre implantation avec ube utilisation multithreadé (une même pile utlisé par plusieurs threads). Cela fonctionne-t-il ? +3. Ajoutez des primitives d'exclusions mutuelles afin de garantir un comportement cohérent et déterministe dans le cas d’une exécution multi-threadée. + + +#### Ex4 (Mutltiplication matrice/vecteur, problème du false sharing) +Le but de l'exercice est de parallèliser le calcul du produit matrice/vecteur. + +Pour rappel, le produit d'une matrice `A[N][P]` par un vecteur `x[P]` donne un vecteur +`y[N]` par : + +```c +for(i=0;i + + nb ThreadsDimensions + + 8000000x88000x80008x8000000 + tempstempstemps + 1 + 2 + 4 + 8 + + + + Que constatez-vous pour la dernière colonne ? + [ chaque processeur utilise un cache de premier niveau (L1) dont les lignes font + 64 octets. Les composantes du vecteur `y` ne sont pas accèder de manière concurrente. Mais il se peut qu'une ligne d'un cache contienne une composante écrite par un autre thread dans un autre cache rendant la ligne ```dirty``` ] + + Modifiez le code pour remédier au problème. + + + diff --git a/tp/tp6/src/a.out b/tp/tp6/src/a.out new file mode 100755 index 0000000..b0b356b Binary files /dev/null and b/tp/tp6/src/a.out differ diff --git a/tp/tp6/src/ex1.c b/tp/tp6/src/ex1.c new file mode 100644 index 0000000..3500d87 --- /dev/null +++ b/tp/tp6/src/ex1.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +#define NUM_THREADS 16 + +void *thread(void *thread_id) +{ + int id = *((int *) thread_id); + printf("Hello from thread %d\n", id); + + return NULL; +} + +int main(int argc, char *argv[]) +{ + pthread_t threads[NUM_THREADS]; + for (int i = 0; i < NUM_THREADS; i++) + assert( pthread_create(&threads[i], NULL, thread, &i) == 0); + + for (int i = 0; i < NUM_THREADS; i++) + assert( pthread_join(threads[i], NULL) == 0); + + return EXIT_SUCCESS; +} + diff --git a/tp/tp6/src/pi.c b/tp/tp6/src/pi.c new file mode 100644 index 0000000..dbc7de5 --- /dev/null +++ b/tp/tp6/src/pi.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +void* nbDansCercleSeq( void* nbLancers ) +{ + long nb = 0; + unsigned int seed; + for( long i = 0; i < (long) nbLancers; i++ ) { + double x = (double) rand_r(&seed) / RAND_MAX; + double y = (double) rand_r(&seed) / RAND_MAX; + if ( x * x + y * y <= 1.0 ) { + nb += 1; + } + } + pthread_exit( (void*) nb ); // <--- on triche ici !!! +} + +double evaluerPi( long nbLancers , long nbThreads ) +{ + long nbTotalDansCercle = 0; + + // TODO + // + return 4.0 * nbTotalDansCercle / nbLancers; +} + + +static inline double tstamp(void) +{ + struct timespec tv; + clock_gettime(CLOCK_MONOTONIC, &tv); + return tv.tv_sec + tv.tv_nsec * 1.0e-9; +} + +int main( int argc , char *argv[] ) +{ + assert( argc >= 3 ); + long nbLancers = strtol(argv [1], NULL, 0); + assert( nbLancers > 0 ); + long nbThreads = strtol(argv [2], NULL, 0); + assert( nbThreads > 0 ); + double t1,t2; + t1 = tstamp(); + double pi = evaluerPi(nbLancers, nbThreads); + t2 = tstamp(); + printf( "pi = %f time = %f\n",pi, t2-t1); + return 0; +} diff --git a/tp/tp6/src/stack/Makefile b/tp/tp6/src/stack/Makefile new file mode 100644 index 0000000..28447ff --- /dev/null +++ b/tp/tp6/src/stack/Makefile @@ -0,0 +1,10 @@ +stack.o : stack.c + gcc -c stack.c + +main.o : main.c stack.h + gcc -c main.c + +main : main.o stack.o + gcc -o main main.o stack.o + +all : main diff --git a/tp/tp6/src/stack/main.c b/tp/tp6/src/stack/main.c new file mode 100644 index 0000000..514a427 --- /dev/null +++ b/tp/tp6/src/stack/main.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include "stack.h" + + + +int main(int argc, char *argv[]) +{ + + int val; + stack_t * s=stack_create(20); + + for(int i=0;i<20; i++) + stack_push(s,i); + + for(int i=0;i<20; i++) + stack_pop(s,&val); + + return 0; +} diff --git a/tp/tp6/src/stack/stack.c b/tp/tp6/src/stack/stack.c new file mode 100644 index 0000000..d1cc620 --- /dev/null +++ b/tp/tp6/src/stack/stack.c @@ -0,0 +1,32 @@ +#include "stack.h" +#include +#include + +struct stack_t { + /* + votre implantation + + */ +}; + +stack_t * stack_create( int max_size) +{ + +} + + +int stack_destroy(stack_t * s) +{ + +} + +int stack_push(stack_t *s,int val) +{ + +} + +int stack_pop(stack_t *s,int * val) +{ + +} + diff --git a/tp/tp6/src/stack/stack.h b/tp/tp6/src/stack/stack.h new file mode 100644 index 0000000..24768ec --- /dev/null +++ b/tp/tp6/src/stack/stack.h @@ -0,0 +1,12 @@ +#ifndef _STACK_INT_H +#define _STACK_INT_H + +typedef struct stack_t stack_t; + +stack_t * stack_create(int max_size); +int stack_destroy(stack_t *s); +int stack_push(stack_t *s, int val); +int stack_pop(stack_t *s,int *val); + + +#endif