ajout tp- et cm thread

This commit is contained in:
2025-10-08 10:24:45 +02:00
parent a677d98c2c
commit 348e3b73d8
9 changed files with 315 additions and 0 deletions

View File

@@ -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).

160
tp/tp6/README.md Normal file
View File

@@ -0,0 +1,160 @@
# TP : Threads
#### Ex1
```c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
#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 lexécution de ce programme est correcte? Vous pouvez vous en assurer en lexécutant plusieurs fois.
2. Si vous pensez (et avez constaté) que ce nest pas le cas, expliquez pourquoi.
3. Modifiez le code pour quil donne le résultat attendu.
#### Ex2
On veut écrire un programme calculant la somme des entiers
de `1` à `N` à laide de `M` threads. Chaque thread calculera la somme
dun 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 quils 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 :
- Limplé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 lutilisateur (ex : N=20, M=8).
- Évitez dutiliser 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 dune 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<N;i++){
y[i]=0;
for(j=0;j<P;j++)
y[i] += A[i][j]*x[j]
}
```
1. Écrire un programme qui prend en argument un entier `n`, et qui crée autant de threads pour
le cacul du produit. Chaque thread recevra en argument l'intervalle des indices `i in [start,end]` pour lequels il doit
effectuer le calcul `y[i]`. Pour le test, utilisez des matrices de type `int` en variables globales préalablement
initialisées aléatoirement.
2. Remplissez le tableau suivant :
<table>
<tbody>
<tr><td rowspan=3>nb Threads</td><td colspan=3>Dimensions</td>
</tr>
<tr><td>8000000x8</td><td>8000x8000</td><td>8x8000000</td></tr>
<tr><td>temps</td><td>temps</td><td>temps</td></tr>
<tr><td>1</td><td></td><td></td><td></td></tr>
<tr><td>2</td><td></td><td></td><td></td></tr>
<tr><td>4</td><td></td><td></td><td></td></tr>
<tr><td>8</td><td></td><td></td><td></td></tr>
</tbody>
</table>
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.

BIN
tp/tp6/src/a.out Executable file

Binary file not shown.

27
tp/tp6/src/ex1.c Normal file
View File

@@ -0,0 +1,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
#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;
}

50
tp/tp6/src/pi.c Normal file
View File

@@ -0,0 +1,50 @@
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
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;
}

10
tp/tp6/src/stack/Makefile Normal file
View File

@@ -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

21
tp/tp6/src/stack/main.c Normal file
View File

@@ -0,0 +1,21 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#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;
}

32
tp/tp6/src/stack/stack.c Normal file
View File

@@ -0,0 +1,32 @@
#include "stack.h"
#include <stdlib.h>
#include <assert.h>
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)
{
}

12
tp/tp6/src/stack/stack.h Normal file
View File

@@ -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