Skip to content
Snippets Groups Projects
tp.c 7.37 KiB
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <time.h>

#define CAMION_CAPACITE 4

typedef struct {
    sem_t velos;
    sem_t bornes;
    int velos_dispo;
    int personnes_attente;
    pthread_mutex_t mutex;
} Site;

int SITES, HABITANTS, TRAJETS, BORNES;
Site *sites;
pthread_mutex_t mutex_trajets = PTHREAD_MUTEX_INITIALIZER;
int trajets_effectues = 0;
int velos_depot = 0;
pthread_mutex_t mutex_velos_depot = PTHREAD_MUTEX_INITIALIZER;

void *habitant(void *arg) {
    int id = *(int *)arg;
    int site_actuel = rand() % SITES;
    free(arg);
    
    for (int i = 0; i < TRAJETS; i++) {
        int site_suivant;
        do {
            site_suivant = rand() % SITES;
        } while (site_suivant == site_actuel);

        pthread_mutex_lock(&sites[site_actuel].mutex);
        sites[site_actuel].personnes_attente++;
        pthread_mutex_unlock(&sites[site_actuel].mutex);
        
        printf("(GET) Habitant %d attend un vélo au site %d\n", id, site_actuel);
        sem_wait(&sites[site_actuel].velos);
        
        pthread_mutex_lock(&sites[site_actuel].mutex);
        sites[site_actuel].velos_dispo--;
        sites[site_actuel].personnes_attente--;
        pthread_mutex_unlock(&sites[site_actuel].mutex);
        
        printf("(GET) Habitant %d prend un vélo au site %d\n", id, site_actuel);
        sem_post(&sites[site_actuel].bornes);
        //usleep((rand() % 1000 + 1000));
    
        pthread_mutex_lock(&sites[site_suivant].mutex);
        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", id, site_suivant);
        sem_wait(&sites[site_suivant].bornes);
        
        pthread_mutex_lock(&sites[site_suivant].mutex);
        sites[site_suivant].velos_dispo++;
        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", id, site_suivant);
        //usleep((rand() % 1000 + 1000));
        
        site_actuel = site_suivant;
        
        pthread_mutex_lock(&mutex_trajets);
        trajets_effectues++;
        pthread_mutex_unlock(&mutex_trajets);
    }
    return NULL;
}

void *gestion_camion(void *arg) {
    int velos_camion = 2;
    while (1) {
        pthread_mutex_lock(&mutex_trajets);
        if (trajets_effectues >= HABITANTS * TRAJETS) {
            pthread_mutex_unlock(&mutex_trajets);
            printf("Camion arrête son travail, tous les trajets sont effectués.\n");
            break;
        }
        pthread_mutex_unlock(&mutex_trajets);
        
        for (int i = 0; i < SITES; i++) {
            pthread_mutex_lock(&sites[i].mutex);
            
            // Fixed truck logic - ensure atomic operations with proper locking
            if (sites[i].velos_dispo > BORNES - 2 && velos_camion < CAMION_CAPACITE) {
                int aRetirer = sites[i].velos_dispo - (BORNES - 2);
                if (aRetirer > CAMION_CAPACITE - velos_camion)
                    aRetirer = CAMION_CAPACITE - velos_camion;
                
                // Ensure we don't remove too many bikes
                if (aRetirer > sites[i].velos_dispo-1)
                    aRetirer = sites[i].velos_dispo-1;
                
                for (int j = 0; j < aRetirer; j++) {
                    sem_wait(&sites[i].velos);
                    sites[i].velos_dispo--;
                    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);
            } 
            else if (sites[i].velos_dispo < 2 && velos_camion > 0) {
                int bikes_to_add = 2 - sites[i].velos_dispo;
                if (bikes_to_add > velos_camion)
                    bikes_to_add = velos_camion;
                
                int available_slots = BORNES - sites[i].velos_dispo;
                if (bikes_to_add > available_slots)
                    bikes_to_add = available_slots;
                
                for (int j = 0; j < bikes_to_add; j++) {
                    sem_wait(&sites[i].bornes);
                    sites[i].velos_dispo++;
                    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);
            }
            
            pthread_mutex_unlock(&sites[i].mutex);
            usleep((rand() % 100 + 100));
        }
        
        pthread_mutex_lock(&mutex_velos_depot);
        if (velos_camion > 2) {
            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);
        } else if (velos_camion < 2 && velos_depot > 0) {
            int needed = 2 - velos_camion;
            if (needed > velos_depot)
                needed = velos_depot;
            velos_depot -= needed;
            velos_camion += needed;
            printf("Camion prend des vélos du 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);
        usleep((rand() % 100 + 100));
    }
    return NULL;
}

int main(int argc, char *argv[]) {
    if (argc != 5) {
        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]);
    
    srand(time(NULL));
    sites = malloc(SITES * sizeof(Site));
    
    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);
        pthread_mutex_init(&sites[i].mutex, NULL);
        sites[i].velos_dispo = BORNES - 2;
        sites[i].personnes_attente = 0;
    }
    
    for (int i = 0; i < HABITANTS; i++) {
        int *id = malloc(sizeof(int));
        *id = i;
        pthread_create(&habitants[i], NULL, habitant, id);
    }
    pthread_create(&camion, NULL, gestion_camion, NULL);
    
    for (int i = 0; i < HABITANTS; i++) {
        pthread_join(habitants[i], 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+= 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++) {
        sem_destroy(&sites[i].velos);
        sem_destroy(&sites[i].bornes);
        pthread_mutex_destroy(&sites[i].mutex);
    }
    pthread_mutex_destroy(&mutex_trajets);
    pthread_mutex_destroy(&mutex_velos_depot);
    free(sites);
    return 0;
}