diff --git a/TP3_rapport_bykes.txt b/TP3_rapport_bykes.txt new file mode 100644 index 0000000000000000000000000000000000000000..07531e4b451fb5647b28b4d7d4d50e8ad64c5d62 --- /dev/null +++ b/TP3_rapport_bykes.txt @@ -0,0 +1,99 @@ +TP3 : Gestion d’un parc de vélos + +Nom : El Ajeri Nom : Davila Prado +Prénom : Khalil Mokhtar Prénom : Lou + +Groupe : 14 + +-------------------------------------------------- +Statut du projet +-------------------------------------------------- +Projet fonctionnel. + +- Le programme gère correctement la concurrence entre threads à l’aide de mutex et sémaphores. +- Tous les trajets sont effectués sans blocage (tests répétés). +- Le nombre total de vélos reste constant à la fin de la simulation : S * (N - 2) + 2. +- Chaque site possède entre 0 et N vélos à la fin. +- Les affichages reflètent bien les prises, dépôts, attentes et les actions du camion. +- La logique du dépôt et du rééquilibrage est bien gérée. +- Les délais usleep ont été désactivés pour les tests de performance/stabilité. +- On a eu un bug avec un grand nombre d'habitants donc à cause de la concurrence au niveau de la gestion des vélos + qu'on a pu régler par la suite. + +-------------------------------------------------- +Algorithme de gestion des habitants +-------------------------------------------------- +Chaque habitant est un thread. Il effectue M trajets : + +1. Il attend passivement qu’un vélo soit disponible sur son site actuel (sémaphore velos), en incrémentant personnes_attente. +2. Une fois le vélo obtenu, il décrémente le compteur local velos_dispo du site, puis libère une borne (bornes). +3. Il choisit un autre site (aléatoirement) et attend passivement qu’une borne soit libre (sémaphore bornes) pour y déposer le vélo. +4. Il incrémente alors velos_dispo de ce site, poste sur le sémaphore velos, et libère ainsi le vélo pour un autre utilisateur. + +Toutes les modifications des variables critiques (velos_dispo, personnes_attente) sont protégées par un mutex par site. + +Un mutex global (mutex_trajets) est utilisé pour suivre le nombre total de trajets réalisés par tous les habitants. + + +-------------------------------------------------- +Gestion de la concurrence +-------------------------------------------------- +- Les accès partagés (velos_dispo, bornes, velos, personnes_attente, variables utilisées dans les printf) sont protégés par des mutex individuels. +- Les accès globaux (trajets_effectues, velos_depot) sont protégés par des mutex globaux. +- Les sémaphores assurent des attentes passives : + - velos pour prendre un vélo. + - bornes pour déposer un vélo. +- Les sections critiques sont réduites au strict minimum. +- Chaque affichage est fait après la section critique pour limiter la contention. + +-------------------------------------------------- +Fonctions codées: +-------------------------------------------------- + +void *habitant(void *arg) +--------------------------------- +Cette fonction représente le comportement d’un habitant modélisé par un thread. +- Chaque habitant commence à un site choisi aléatoirement. +- Il effectue TRAJETS fois la séquence de prise et dépôt de vélo entre deux sites différents. +- Il utilise les sémaphores pour attendre passivement la disponibilité d’un vélo ou d’une borne. +- Les compteurs internes (velos_dispo, personnes_attente) sont mis à jour dans des sections critiques protégées par mutex. +- Le compteur global trajets_effectues est également protégé par un mutex. +- À chaque dépôt de vélo, le site actuel est mis à jour. +- Les affichages indiquent les actions de l’habitant et les situations d’attente. + +void *gestion_camion(void *arg) +--------------------------------- +Cette fonction modélise la camionnette de maintenance qui équilibre les vélos entre les sites. +- Elle tourne tant que tous les trajets ne sont pas effectués (condition vérifiée avec mutex_trajets). +- Pour chaque site : + a. Si trop de vélos : enlève jusqu’à CAMION_CAPACITE - velos_camion vélos pour atteindre N - 2. + b. Si trop peu de vélos : ajoute jusqu’à 2 vélos selon disponibilité du camion et bornes. +- Après la boucle des sites : + a. Dépôt des vélos excédentaires si velos_camion > 2. + b. Recharge depuis le dépôt si velos_camion < 2. +- L’accès au dépôt est protégé par mutex_velos_depot. +- Le comportement respecte la capacité max du camion (4 vélos). + +int main(int argc, char *argv[]) +--------------------------------- +Fonction principale qui : +- Récupère les paramètres SITES, HABITANTS, TRAJETS et BORNES depuis la ligne de commande. +- Initialise les sémaphores et mutex de chaque site. +- Lance les threads pour chaque habitant et un thread pour le camion. +- Attend la fin de tous les threads avec pthread_join. +- Affiche les vélos par site et la vérification du total global à la fin de l’exécution. +- Détruit les sémaphores et mutex à la fin. + +-------------------------------------------------- +Bugs résiduels +-------------------------------------------------- + +Lorsqu'un trop grand nombre d'habitants est spécifié au lancement du programme, le programme finit par se bloquer après un certain temps d'exécution. +Nous pensons que ceci est dû à un trop grand nombre de threads concurrents crées par rapport à la capacité de la machine. +Il faudrait probablement limiter le nombre de threads créés simultanement pour éviter ce genre de problème. + +-------------------------------------------------- +Conclusion +-------------------------------------------------- + +Le programme respecte toutes les exigences du TP : cohérence des vélos, absence de blocage, affichages pertinents, gestion propre de la concurrence. \ No newline at end of file diff --git a/byke_simulation b/byke_simulation new file mode 100755 index 0000000000000000000000000000000000000000..d298e633a2e0004481d7f67a985035fc5c59da0c Binary files /dev/null and b/byke_simulation differ diff --git a/tp b/tp deleted file mode 100755 index 11586c6855566ccba201f878ee9431e295a73610..0000000000000000000000000000000000000000 Binary files a/tp and /dev/null differ diff --git a/tp.c b/tp.c index b37678fe2e3f4cc517124f9ab91ac389c7f7aebc..70e4f8f2755b0c859760836c03bdadb8fb845a0c 100644 --- a/tp.c +++ b/tp.c @@ -1,3 +1,6 @@ +/*Authors: Lou Davila Prado, Khalil El Ajeri + Groupe: 14*/ + #include <stdio.h> #include <stdlib.h> #include <pthread.h> @@ -14,7 +17,7 @@ typedef struct int velos_dispo; int personnes_attente; pthread_mutex_t mutex; -} Site; +}Site; int SITES,HABITANTS,TRAJETS,BORNES; Site *sites; @@ -36,38 +39,46 @@ void *habitant(void *arg) { site_suivant = rand()%SITES; } - while (site_suivant == site_actuel); + while (site_actuel == site_suivant); pthread_mutex_lock(&sites[site_actuel].mutex); sites[site_actuel].personnes_attente++; + int velos = sites[site_actuel].velos_dispo; + int attente = sites[site_actuel].personnes_attente; pthread_mutex_unlock(&sites[site_actuel].mutex); - printf("(GET) Habitant %d attend un vélo au site %d\n",habitant_id,site_actuel); + printf("(GET) Habitant %d attend un vélo au site %d (%d vélos, %d personnes en attente)\n", habitant_id, site_actuel, velos, attente); sem_wait(&sites[site_actuel].velos); pthread_mutex_lock(&sites[site_actuel].mutex); sites[site_actuel].velos_dispo--; sites[site_actuel].personnes_attente--; + velos = sites[site_actuel].velos_dispo; + attente = sites[site_actuel].personnes_attente; pthread_mutex_unlock(&sites[site_actuel].mutex); - printf("(GET) Habitant %d prend un vélo au site %d\n",habitant_id,site_actuel); + printf("(GET) Habitant %d prend un vélo au site %d (%d vélos, %d personnes en attente)\n", habitant_id, site_actuel, velos, attente); sem_post(&sites[site_actuel].bornes); //usleep((rand()%1000+1000)); pthread_mutex_lock(&sites[site_suivant].mutex); sites[site_suivant].personnes_attente++; + velos = sites[site_suivant].velos_dispo; + attente = sites[site_suivant].personnes_attente; pthread_mutex_unlock(&sites[site_suivant].mutex); - printf("(PUT) Habitant %d attend d'avoir accès à une borne du site %d\n",habitant_id,site_suivant); + printf("(PUT) Habitant %d attend d'avoir accès à une borne du site %d (%d vélos, %d personnes en attente)\n", habitant_id, site_suivant, velos, attente); sem_wait(&sites[site_suivant].bornes); pthread_mutex_lock(&sites[site_suivant].mutex); sites[site_suivant].velos_dispo++; sites[site_suivant].personnes_attente--; + velos = sites[site_suivant].velos_dispo; + attente = sites[site_suivant].personnes_attente; pthread_mutex_unlock(&sites[site_suivant].mutex); sem_post(&sites[site_suivant].velos); - printf("(PUT) Habitant %d dépose un vélo au site %d\n",habitant_id,site_suivant); + printf("(PUT) Habitant %d dépose un vélo au site %d (%d vélos, %d personnes en attente)\n", habitant_id, site_suivant, velos, attente); //usleep((rand()%1000+1000)); site_actuel = site_suivant; @@ -96,6 +107,8 @@ void *gestion_camion(void *arg) for (int i = 0; i < SITES; i++) { pthread_mutex_lock(&sites[i].mutex); + int velos = sites[i].velos_dispo; + int attente = sites[i].personnes_attente; if (CAMION_CAPACITE > velos_camion && sites[i].velos_dispo > BORNES-2) { @@ -110,15 +123,23 @@ void *gestion_camion(void *arg) aRetirer = sites[i].velos_dispo-1; } + pthread_mutex_unlock(&sites[i].mutex); + for (int j = 0; j < aRetirer; j++) { sem_wait(&sites[i].velos); + + pthread_mutex_lock(&sites[i].mutex); sites[i].velos_dispo--; + velos = sites[i].velos_dispo; + attente = sites[i].personnes_attente; + pthread_mutex_unlock(&sites[i].mutex); + velos_camion++; sem_post(&sites[i].bornes); } - printf("Camion prend des vélos au site %d (Vélos dans camion: %d)\n",i,velos_camion); + printf("Camion prend %d vélos au site %d (%d vélos, %d personnes en attente) (Vélos dans le camion: %d)\n", aRetirer, i, velos, attente, velos_camion); } else if (sites[i].velos_dispo < 2 && velos_camion > 0) { @@ -134,18 +155,29 @@ void *gestion_camion(void *arg) aAjouter = spotsDisponibles; } + pthread_mutex_unlock(&sites[i].mutex); + for (int j = 0; j < aAjouter; j++) { sem_wait(&sites[i].bornes); + + pthread_mutex_lock(&sites[i].mutex); sites[i].velos_dispo++; + velos = sites[i].velos_dispo; + attente = sites[i].personnes_attente; + pthread_mutex_unlock(&sites[i].mutex); + velos_camion--; sem_post(&sites[i].velos); } - printf("Camion dépose des vélos au site %d (Vélos dans camion: %d)\n",i,velos_camion); + printf("Camion dépose %d vélos au site %d (%d vélos, %d personnes en attente) (Vélos dans le camion: %d)\n", aAjouter, i, velos, attente, velos_camion); + } + else + { + pthread_mutex_unlock(&sites[i].mutex); } - pthread_mutex_unlock(&sites[i].mutex); //usleep((rand()%100+100)); } @@ -154,7 +186,7 @@ void *gestion_camion(void *arg) { velos_depot+= (velos_camion-2); velos_camion = 2; - printf("Camion vide les vélos au dépôt (Vélos en dépôt: %d)\n",velos_depot); + printf("Camion vide les vélos au dépôt (Vélos en dépôt: %d)\n", velos_depot); } else if (velos_depot > 0 && velos_camion < 2) { @@ -165,11 +197,11 @@ void *gestion_camion(void *arg) } velos_depot-= requis; velos_camion+= requis; - printf("Camion prend des vélos du dépôt (Vélos en dépôt: %d)\n",velos_depot); + printf("Camion prend des vélos au dépôt (Vélos en dépôt: %d)\n", velos_depot); } pthread_mutex_unlock(&mutex_velos_depot); - printf("Camion fait un tour, vélos restants: %d, vélos en dépôt: %d\n",velos_camion,velos_depot); + printf("Camion fait un tour, Vélos restants: %d, vélos en dépôt: %d\n", velos_camion, velos_depot); //usleep((rand()%100+100)); } return NULL; @@ -179,23 +211,31 @@ int main(int argc, char *argv[]) { if (argc != 5) { - fprintf(stderr, "Usage: %s <SITES> <HABITANTS> <TRAJETS> <BORNES>\n",argv[0]); + fprintf(stderr, "Usage: %s <SITES> <HABITANTS> <TRAJETS> <BORNES>\n", argv[0]); return 1; } SITES = atoi(argv[1]); HABITANTS = atoi(argv[2]); TRAJETS = atoi(argv[3]); BORNES = atoi(argv[4]); + + if (SITES <= 2 || HABITANTS <= 2 || TRAJETS <= 0 || BORNES <= 4) + { + printf("Les contraintes suivantes doivent être respectées:\n"); + printf("SITES > 2, HABITANTS > 2, TRAJETS > 0, BORNES > 4\n"); + exit(EXIT_FAILURE); + } + srand(time(NULL)); sites = malloc(SITES * sizeof(Site)); - pthread_t habitants[HABITANTS],camion; + pthread_t habitants[HABITANTS], camion; for (int i = 0; i < SITES; i++) { - sem_init(&sites[i].velos,0,BORNES-2); - sem_init(&sites[i].bornes,0,2); + sem_init(&sites[i].velos, 0, BORNES-2); + sem_init(&sites[i].bornes, 0, 2); pthread_mutex_init(&sites[i].mutex, NULL); sites[i].velos_dispo = BORNES-2; sites[i].personnes_attente = 0; @@ -204,24 +244,24 @@ int main(int argc, char *argv[]) { int *habitant_id = malloc(sizeof(int)); *habitant_id = i; - pthread_create(&habitants[i],NULL,habitant,habitant_id); + pthread_create(&habitants[i], NULL, habitant, habitant_id); } - pthread_create(&camion,NULL,gestion_camion,NULL); + pthread_create(&camion, NULL, gestion_camion, NULL); for (int i = 0; i < HABITANTS; i++) { - pthread_join(habitants[i],NULL); + pthread_join(habitants[i], NULL); } - pthread_join(camion,NULL); + pthread_join(camion, NULL); int total_velos = velos_depot; for (int i = 0; i < SITES; i++) { - total_velos+= sites[i].velos_dispo; - printf("Site %d contains %d bykes\n",i,sites[i].velos_dispo); + total_velos += sites[i].velos_dispo; + printf("Site %d contient %d vélos\n", i, sites[i].velos_dispo); } - total_velos+= 2; - printf("Nombre total de vélos à la fin : %d (doit être %d)\n",total_velos,SITES*(BORNES-2)+2); + total_velos += 2; + printf("Nombre total de vélos à la fin : %d (doit être %d)\n", total_velos, SITES*(BORNES-2)+2); printf("Simulation terminée.\n"); for (int i = 0; i < SITES; i++)