/* parking.c */

#include <stdio.h>
#include <pthread.h>
#define N 5              //Nombre de places dans le parking
#define NbTh 10      //Nombre de processus symbolisant les voitures

pthread_t tid[NbTh];
pthread_mutex_t mutex;
pthread_cond_t cond;

//initialisations
int NbEntrant=0;    //Nombre de voitures voulant emprunter la passerelle pour entrer dans le parking
int NbSortant=0;    //Nombre de voitures voulant emprunter la passerelle pour sortir du parking
int NbV=0;          //Nombre de voitures garées dans le parking

void Demander_a_emprunter_la_passerelle ()
{
pthread_mutex_lock(&mutex);
        while(((NbV + NbEntrant)>N-1) || (NbSortant>0))
                pthread_cond_wait(&cond,&mutex);
        NbEntrant++;
pthread_mutex_unlock(&mutex);
}

void Se_Garer()
{
pthread_mutex_lock(&mutex);
        NbEntrant--;
        NbV++;
        pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
}

void Demander_a_Sortir ()
{
pthread_mutex_lock(&mutex);
        NbSortant++;
        while(NbEntrant>0)
                pthread_cond_wait(&cond,&mutex);
        NbV--;
        pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
}

void Quitter_la_Passerelle()
{
pthread_mutex_lock(&mutex);
    NbSortant--;
    pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
}

void * fonc(void * i)
{
srand(pthread_self());
printf("La voiture %d veut emprunter la passerelle pour entrer dans le parking\n",(int)i);
Demander_a_emprunter_la_passerelle();
// temps de la traversee de la passerelle
printf("La voiture %d emprunte la passerelle pour se garer \n", (int)i);
usleep(1000);
printf("La voiture %d se gare\n",(int) i);
Se_Garer();
// le temps passe dans le parking
usleep(rand()%1000000);
printf("La voiture %d veut emprunter la passerelle pour sortir du parking\n",(int)i);
Demander_a_Sortir ();
printf("La voiture %d sort du parking et emprunte la passerelle\n",(int)i);
//temps de la traversee de la passerelle
usleep(1000);
Quitter_la_Passerelle();
printf("La voiture %d quitte la passerelle\n", (int)i);
}

int main()
{
int num,i;
pthread_mutex_init(&mutex,0);
pthread_cond_init(&cond,0);

//creation des threads
for(num=0;num<NbTh;num ++)
        pthread_create(tid+num,0,(void *(*)())fonc,(void*)num);

//attend la fin de tous les processus
for(num=0;num<NbTh;num ++)
        pthread_join(tid[num],NULL);
        
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
exit(0);
}
