diff --git a/README.md b/README.md index f61bacb..d19b3c8 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,9 @@ Rappels sur la gestion de la [mémoire](cours/memoire.pdf), [td1](td/td1/td1.pdf #### Semaine 5 (28/09 - 02-10) [Signaux](cours/signaux.pdf), [td5](td/td5/td5.pdf), [tp5](tp/tp5). +### Semaine 6 (05/10 - 09/10) +[Tubes, redirections](cours/pipe.pdf), [td6](td/td6/td6.pdf), [tp6](tp/tp6). + diff --git a/tp/tp6/README.md b/tp/tp6/README.md new file mode 100644 index 0000000..c0eb635 --- /dev/null +++ b/tp/tp6/README.md @@ -0,0 +1,77 @@ +# Redirections, tubes, synchronisation + +#### Ex1 +Soit le graphe de processus suivant (un tube est établi entre Pf2 et +Pf1f1) + +```bash + | P + |____ + | \ Pf1 + | \ + | \ + |\Pf2 |\ + | \ | \Pf1f1 + | \ | \ + O O O O + ()-->--() +``` + +1. Ecrivez un programme pipe-ex.c qui implante le graphe ci-dessus + (y compris le tube) et tel que : + - Pf2 écrive en permanence toutes les 3 secondes son PID dans + le tube en affichant ce qu'il écrit + - Pf1f1 lise en permanence chaque seconde depuis tube + `sizeof(pid_t)` en affichant ce qu'il lit + + Vérifiez que le programme fonctionne comme prévu, i.e il affiche + : + + ```bash + 16411 sent 16411 + 16412 received 16411 + 16411 sent 16411 + 16412 received 16411 + ..... + + ``` + +2. Lancez le programme ci-dessus et faites les essais suivants + (relancez le programme après chaque essai). Expliquez à chaque + fois vos observations. + 1. Envoyez le signal `SIGSTOP` à Pf2, puis le signal SIGCONT à + Pf2. + 2. Envoyez le signal `SIGSTOP` à Pf1f1, puis le signal SIGCONT à + Pf1f1. + 3. Envoyez le signal `SIGTERM` à Pf2. + 4. Envoyez le signal `SIGTERM` à Pf1f1. +3. Modifiez le programme pipe-ex.c en assurant que tous les + processus ferment les descripteurs du tube non utilisés. Faites + les mêmes essais que ci-dessus et expliquez ce que vous + observez. +4. Modifiez encore une fois le programme pipe-ex.c pour que les + deux processus Pf1, Pf2 écrivent dans le tube simultanement et + que seul Pf1f1 le lise. Qu'observez-vous ? + +#### Ex1 +Reprendre l'[exercice 1](../tp5/parallelisme.md) du tp précédent. Vous devez utiliser comme +seul moyen de communication, entre les fils et le pere, des tubes (plus de `mmap`). +Les processus fils, à la création, ne savent pas quelle tranche ils doivent sommer. + +1. De combien de tubes a-t-on besoin ? +2. On rappelle que l'écriture dans un tube est atomique jusqu'à `PIPE_BUF`. +3. Écrire le programme correspondant. + + +#### Ex2 +Il s'agit d'un [exercice](./src/billes.c) classique de synchronisation. Des billes, dans une zone rectangulaire, se déplacent en rebodissant +sur les parois et les unes sur les autres. Chaque bille est un processus. L'état global est une zone partagée, protégée +en écriture par un sémaphore (cf cours). + +L'affichage graphique est géré par le processus père (superviseur). Chaque bille, après mise à jour de sa position, +envoie un message au superviseur par un tube qui peut mettre à jour la fenêtre d'affichage. **Seule cette partie est à compléter**. + +
+ +
+ diff --git a/tp/tp6/billes.png b/tp/tp6/billes.png new file mode 100644 index 0000000..e0bcea4 Binary files /dev/null and b/tp/tp6/billes.png differ diff --git a/tp/tp6/src/billes.c b/tp/tp6/src/billes.c new file mode 100644 index 0000000..38d01b0 --- /dev/null +++ b/tp/tp6/src/billes.c @@ -0,0 +1,175 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NB_BILLES 20 +#define LARGEUR 640 +#define HAUTEUR 480 +#define RAYON 12 +#define FPS_DELAY_US 16000 + +/* ========================================================= + * ÉTAT D'UNE BILLE + MESSAGE D'AFFICHAGE + ZONE PARTAGÉE + * ========================================================= */ + +typedef struct { + float x, y, vx, vy; /* position + vitesse */ +} etat_bille_t; + +typedef struct { + int id; + float x, y; /* position sur la grille */ +} msg_bille_t; + +typedef struct { + etat_bille_t billes[NB_BILLES]; + sem_t sem_shm; /* protège billes[] */ +} zone_partagee_t; + +/* ========================================================= + * PROCESSUS "BILLE" (fils) + * ========================================================= */ + +void processus_bille(int id, int fd_ecriture, zone_partagee_t *zone) { + while (1) { + sem_wait(&zone->sem_shm); + etat_bille_t *b = &zone->billes[id]; + + b->x += b->vx; + b->y += b->vy; + + if (b->x - RAYON < 0) { b->x = RAYON; b->vx = -b->vx; } + if (b->x + RAYON > LARGEUR) { b->x = LARGEUR - RAYON; b->vx = -b->vx; } + if (b->y - RAYON < 0) { b->y = RAYON; b->vy = -b->vy; } + if (b->y + RAYON > HAUTEUR) { b->y = HAUTEUR - RAYON; b->vy = -b->vy; } + + for (int j = id + 1; j < NB_BILLES; j++) { + etat_bille_t *autre = &zone->billes[j]; + float dx = autre->x - b->x; + float dy = autre->y - b->y; + float dist = sqrtf(dx * dx + dy * dy); + + if (dist > 0.0f && dist < 2.0f * RAYON) { + float nx = dx / dist, ny = dy / dist; + float overlap = 2.0f * RAYON - dist; + + b->x -= nx * overlap / 2.0f; + b->y -= ny * overlap / 2.0f; + autre->x += nx * overlap / 2.0f; + autre->y += ny * overlap / 2.0f; + + float v1n = b->vx * nx + b->vy * ny; + float v2n = autre->vx * nx + autre->vy * ny; + float diff = v2n - v1n; + + b->vx += diff * nx; + b->vy += diff * ny; + autre->vx -= diff * nx; + autre->vy -= diff * ny; + } + } + + msg_bille_t m = ; /* <- TODO */ + sem_post(&zone->sem_shm); + + write(); /* <- TODO */ + + usleep(FPS_DELAY_US); + } +} + +/* ========================================================= + * PROCESSUS SUPERVISEUR (parent) + * ========================================================= */ + +void processus_superviseur(int fd_lecture) { + Display *dpy = XOpenDisplay(NULL); + + assert(dpy != 0); + + int screen = DefaultScreen(dpy); + Window win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), + 0, 0, LARGEUR, HAUTEUR, 1, + BlackPixel(dpy, screen), WhitePixel(dpy, screen)); + XSelectInput(dpy, win, ExposureMask | KeyPressMask); + XMapWindow(dpy, win); + GC gc = XCreateGC(dpy, win, 0, NULL); + + float px[NB_BILLES] = {0}, py[NB_BILLES] = {0}; + + msg_bille_t m; + + while (read(fd_lecture, &m, sizeof(m)) == (ssize_t)sizeof(m)) { + if (m.id >= 0 && m.id < NB_BILLES) { + px[m.id] = m.x; + py[m.id] = m.y; + } + + XClearWindow(dpy, win); + for (int i = 0; i < NB_BILLES; i++) { + XFillArc(dpy, win, gc, + (int)px[i] - RAYON, (int)py[i] - RAYON, + RAYON * 2, RAYON * 2, 0, 360 * 64); + } + XFlush(dpy); + } + + XFreeGC(dpy, gc); + XCloseDisplay(dpy); +} + +int main(int argc, char *argv[]) +{ + int fd[2]; /* --- tube : billes -> superviseur --- */ + + assert(pipe(fd) != -1); + + /* --- zone partagée : billes + sémaphore, créée AVANT les fork() --- */ + + zone_partagee_t *zone = mmap(NULL, sizeof(zone_partagee_t), + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + assert(zone != MAP_FAILED); + assert(sem_init(&zone->sem_shm, 1 , 1) != -1); /* --- semaphore --> section critique --- */ + + srand(time(NULL)); + for (int i = 0; i < NB_BILLES; i++) { + zone->billes[i].x = RAYON + rand() % (LARGEUR - 2 * RAYON); + zone->billes[i].y = RAYON + rand() % (HAUTEUR - 2 * RAYON); + zone->billes[i].vx = (rand() % 5 + 2) * (rand() % 2 ? 1 : -1); + zone->billes[i].vy = (rand() % 5 + 2) * (rand() % 2 ? 1 : -1); + } + + for (int i = 0; i < NB_BILLES; i++) { + pid_t pid = fork(); + + assert(pid >= 0); + + if (pid == 0) { + close(fd[0]); /* le fils ne lit pas le tube */ + processus_bille(i, fd[1], zone); + close(fd[1]); + munmap(zone, sizeof(zone_partagee_t)); + exit(0); + } + } + + close(fd[1]); /* le parent n'écrit pas le tube */ + processus_superviseur(fd[0]); + close(fd[0]); + + for (int i = 0; i < NB_BILLES; i++) wait(NULL); + + sem_destroy(&zone->sem_shm); + munmap(zone, sizeof(zone_partagee_t)); + + return 0; +}