// Includes
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <semaphore.h>
// Constantes
#define NB_PERS_MAX 100
#define NB_ATTRACTION 5
#define TIME_ATTRAC_MAX 12
#define PERS_MAX_ATTRAC 10
#define TPS_OUVERTURE_PARC 120
#define ARGENT_MAX 50
#define COUT_MAX 2
// Definition du type state correspondant
// aux états qu'une personne peut avoir
typedef enum
{
ARR = 0, FREE, PAY, QUIT
}STATE;
// Définition de la structure personne
typedef struct
{
int id;
STATE etat;
int temps; // temps passé dans le parc d'attractions
int money; // Optionnel
}PERSONNE;
// Définition de la structure Attraction gratuite
typedef struct
{
int id;
int visite;
}ATTRACTION_FREE;
// Définition de la structure attraction payante
typedef struct
{
int id;
int capacite; // Capacité de l'attraction
int temps; // Durée de l'attraction
int visite;
}ATTRACTION_PAY;
// Structure permmettant de stocker l'id et le nombre de visite de l'attraction la plus visitée
typedef struct
{
int max;
int id;
}SEARCHMAX;
// Variables globales
// Tableau de sémaphore
sem_t* sem;
ATTRACTION_PAY* tabAttrac_P;
ATTRACTION_FREE* tabAttrac_F;
int nbAttrac_P;
int nbAttrac_F;
int temps;
// Prototypes des handlers
void * handlerAttrac (void*);
void * handlerPers (void*);
int timer (void);
int main (void)
{
/// Déclarations
int nbPers;
int i;
SEARCHMAX maxAP;
SEARCHMAX maxAF;
int somme = 0;
PERSONNE* tabPers;
pthread_t* tabThreadP; // Une personne correspond à un thread
// Une attraction payante correspond à un thread
pthread_t* tabThreadAttrac_P;
// Définition des nombres aléatoires
// Génère un nombre aléatoire de personnes entre 1 et 100
nbPers = rand()%NB_PERS_MAX+1;
// Génère un nombre aléatoire d'attraction payante entre 1 et 4
nbAttrac_P = (rand()%(NB_ATTRACTION-1)) + 1;
// Les attractions qui restent sont donc gratuites
nbAttrac_F = NB_ATTRACTION - nbAttrac_P;
// Allocation dynamique pour les personnes
tabPers = (PERSONNE*) malloc (nbPers*sizeof (PERSONNE));
tabThreadP = (pthread_t*) malloc (nbPers*sizeof (pthread_t));
// Allocation dynamique pour les attractions payantes
tabAttrac_P = (ATTRACTION_PAY*) malloc (nbAttrac_P*sizeof (ATTRACTION_PAY));
tabThreadAttrac_P = (pthread_t*) malloc (nbAttrac_P*sizeof (pthread_t));
// Allocation dynamique pour les attractions gratuites
tabAttrac_F = (ATTRACTION_FREE*) malloc (nbAttrac_F*sizeof (ATTRACTION_FREE));
// Allocation dynamique du tableau de semaphore
sem = (sem_t*) malloc (nbAttrac_P*sizeof (sem_t));
// Initialisation des structures personnes
for (i = 0; i < nbPers; i++)
{
tabPers[i].id = i;
tabPers[i].etat = ARR; // Toutes les personnes arrivent
tabPers[i].temps = 0; // Gestion du temps passé dans le parc
tabPers[i].money = rand ()%ARGENT_MAX;
}
// Initialisation des structures attractions payantes et des semaphores
for (i = 0; i < nbAttrac_P; i++)
{
tabAttrac_P[i].id = i;
tabAttrac_P[i].temps = rand()%TIME_ATTRAC_MAX+1;
tabAttrac_P[i].capacite = rand()%PERS_MAX_ATTRAC+1;
tabAttrac_P[i].visite = 0;
tabAttrac_P
[i
].
cout = rand
()%COUT_MAX
+1 ;
sem_init (&sem[i], 0, rand()%PERS_MAX_ATTRAC+1);
}
// Initialisation des structures attractions gratuites
for (i = 0; i < nbAttrac_F; i++)
{
tabAttrac_F[i].id = i;
tabAttrac_F[i].visite = 0;
}
puts ("Bienvenue à DigiWorld ! : OUVERTURE DES PORTES DU PARC" );
// Création des threads pour les personnes
for (i = 0; i < nbPers; i++)
pthread_create (&tabThreadP[i], NULL, handlerPers, &tabPers[i]);
// Création des threads pour les attractions payantes
for (i = 0; i < nbAttrac_P; i++)
pthread_create (&tabThreadAttrac_P[i], NULL, handlerAttrac, NULL);
// Attente des threads
while (temps < TPS_OUVERTURE_PARC)
timer();
for (i = 0; i < nbPers; i++)
pthread_join(tabThreadP[i], NULL);
for (i = 0; i < nbAttrac_P; i++)
pthread_join(tabThreadAttrac_P[i], NULL);
// Expulsion des personnes
for (i = 0; i < nbPers; i++)
{
tabPers[i].etat = QUIT; // Toutes les personnes partent
somme += tabPers[i].temps;
}
puts ("DigiWorld : A Bientot ! : FERMETURE DES PORTES DU PARC" );
// Recherche des max dans les deux types d'attractions
maxAP.max = 0;
maxAP.id = 0;
maxAF.max = 0;
maxAF.id = 0;
// Attractions payantes
for ( i = 0 ; i < nbAttrac_P ; i++)
{
if (tabAttrac_P[i].visite > maxAP.max)
{
maxAP.max = tabAttrac_P[i].visite;
maxAP.id = i;
}
else
{
maxAP.max = maxAP.max;
maxAP.id = maxAP.id;
}
}
// Attractions gratuites
for ( i = 0 ; i < nbAttrac_F ; i++)
{
if (tabAttrac_F[i].visite > maxAF.max)
{
maxAF.max = tabAttrac_F[i].visite;
maxAF.id = i;
}
}
// Résumé de la journée
printf ("%d personnes ont visité le parc aujourd'hui \n", nbPers
);
printf ("et ont passé en moyenne %d min %d s dans le parc \n",
(somme/nbPers
)/
60,
(somme/nbPers
)%
60);
if (nbAttrac_F > 0)
printf ("L'attraction gratuite la plus visitée est l'attraction %d avec %d visites\n", maxAF.
id, maxAF.
max);
printf ("L'attraction payante la plus visitée est l'attraction %d avec %d visites\n", maxAP.
id, maxAP.
max);
// Libération de la mémoire
free (tabPers);
free (tabThreadP);
free (tabAttrac_P);
free (tabThreadAttrac_P);
free (tabAttrac_F);
return 0;
}
// Fonction qui compte le temps
int timer ()
{
sleep(1);
return ++temps;
}
// Fonction pour les threads des attractions payantes
void * handlerAttrac (void* personne)
{
int ind;
PERSONNE * p = (PERSONNE *) personne;
float tmpn;
int actuelTemps;
// Indice aléatoir du tableau
ind = rand()%nbAttrac_P;
// Vérification si la personne est solvable
tmpn = p->money - tabAttrac_P
[ind
].
cout;
if (tmpn < 0)
{
p->etat = (rand ()%2)+1;
handlerPers(p);
return;
}
else
{
actuelTemps = temps;
// TQ que le parc est ouvert on essaye de faire une prise de sémaphore
while (temps < TPS_OUVERTURE_PARC)
{
while (sem_wait (&sem[ind]) == -1);
}
if (temps >= TPS_OUVERTURE_PARC)
{
p->etat = QUIT;
return;
}
else
{
tabAttrac_P[ind].visite++;
p->money -= tabAttrac_P
[ind
].
cout;
p->temps += temps - actuelTemps;
return;
}
}
}
void * handlerPers (void* visiteur)
{
PERSONNE* pers = (PERSONNE*) visiteur;
// TQ on ne dépasse pas le temps d'ouverture du parc
while (temps <= TPS_OUVERTURE_PARC)
{
// Selon l'état dans lequel la personne se trouve...
switch (pers->etat)
{
case ARR :
// Etat initial
// Changement d'état
pers->etat = (rand ()%2)+1;
return;
break;
case FREE:
// Etat Attraction libre
// Incrémentation du temps
pers->temps += (rand()%TPS_OUVERTURE_PARC)+1;
// +1 visite
tabAttrac_F [(rand ()%nbAttrac_F)+1].visite++;
// Changement d'état
pers->etat = (rand ()%3)+1;
return;
break;
case PAY :
// Etat Attraction payante
handlerAttrac(pers);
return;
break;
case QUIT :
// Quitte Digiworld
return;
break;
}
}
pers->etat = QUIT;
return;
}