#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <time.h> #include <string.h> #include <pthread.h> #define ACCOUNT_SIZE 16 #define MAX_NAME_LEN 10 #define FILENAME "../Data/accounts.db" // Couleurs pour l'affichage #define RESET "\033[0m" #define GREEN "\033[32m" #define RED "\033[31m" #define PINK "\033[35m" #define BLUE "\033[34m" typedef struct { int transactions; // Nombre de transactions à effectuer int account_count; // Nombre de comptes disponibles int transactions_done; // Nombre de transactions effectuées int transactions_failed; // Nombre de transactions annulées int total_transfered; // Montant total transféré par le thread } ThreadData; pthread_mutex_t file_mutex; // Mutex pour protéger l'accès au fichier void read_account(int fd, int index, char *name, int *balance) { char buffer[ACCOUNT_SIZE]; // Se positionner à l'index du compte dans le fichier lseek(fd, index * ACCOUNT_SIZE, SEEK_SET); // Lire l'enregistrement du compte read(fd, buffer, ACCOUNT_SIZE); // Extraire le nom et le solde du compte sscanf(buffer, "%7s %d", name, balance); } void write_account(int fd, int index, const char *name, int balance) { char buffer[ACCOUNT_SIZE]; // Formater la chaîne snprintf(buffer, ACCOUNT_SIZE, "%-7s%8d", name, balance); // S'assurer que le buffer est exactement de taille ACCOUNT_SIZE (16) for (int i = strlen(buffer); i < ACCOUNT_SIZE - 1; i++) { buffer[i] = ' '; } buffer[ACCOUNT_SIZE - 1] = '\n'; // Assurer la terminaison avec un saut de ligne // Se positionner à l'index du compte dans le fichier lseek(fd, index * ACCOUNT_SIZE, SEEK_SET); // Écrire l'enregistrement du compte write(fd, buffer, ACCOUNT_SIZE); } void perform_transaction(int fd, int account_count, ThreadData *data) { int from_idx = rand() % account_count; int to_idx = rand() % account_count; while (from_idx == to_idx) { to_idx = rand() % account_count; } char from_name[MAX_NAME_LEN], to_name[MAX_NAME_LEN]; int from_balance, to_balance; pthread_mutex_lock(&file_mutex); // Verrouiller l'accès au fichier read_account(fd, from_idx, from_name, &from_balance); read_account(fd, to_idx, to_name, &to_balance); int max_transfer = from_balance / 5; if (max_transfer > 0) { int transfer_amount = rand() % max_transfer + 1; from_balance -= transfer_amount; to_balance += transfer_amount; write_account(fd, from_idx, from_name, from_balance); write_account(fd, to_idx, to_name, to_balance); // Mise à jour des statistiques data->transactions_done++; data->total_transfered += transfer_amount; printf(GREEN "Transaction : %s -> %s : %d€\n" RESET, from_name, to_name, transfer_amount); } else { data->transactions_failed++; printf(RED "Transaction annulée : Fonds insuffisants pour %s\n" RESET, from_name); } pthread_mutex_unlock(&file_mutex); // Déverrouiller l'accès au fichier } void *thread_transactions(void *arg) { ThreadData *data = (ThreadData *)arg; int fd = open(FILENAME, O_RDWR); if (fd < 0) { perror("Erreur : Impossible d'ouvrir le fichier"); pthread_exit(NULL); } for (int i = 0; i < data->transactions; i++) { perform_transaction(fd, data->account_count, data); usleep(rand() % 100000); } close(fd); pthread_exit(NULL); } int calculate_total_balance() { int fd = open(FILENAME, O_RDONLY); if (fd < 0) { perror("Erreur : Impossible d'ouvrir le fichier"); return -1; } off_t file_size = lseek(fd, 0, SEEK_END); int account_count = file_size / ACCOUNT_SIZE; int total_balance = 0; char name[MAX_NAME_LEN]; int balance; for (int i = 0; i < account_count; i++) { read_account(fd, i, name, &balance); total_balance += balance; } close(fd); return total_balance; } void print_statistics(ThreadData *thread_data, int num_threads) { // En-tête du tableau avec une meilleure mise en forme printf("\n%s--- Statistiques détaillées ---%s\n", PINK, RESET); printf("%-10s%-25s%-25s%-20s\n", "Thread", "Transactions Effectuées", "Transactions Annulées", "Total Transféré (€)"); // Affichage des statistiques de chaque thread for (int i = 0; i < num_threads; i++) { printf("%-10d%-25d%-25d%-20d\n", i+1, thread_data[i].transactions_done, thread_data[i].transactions_failed, thread_data[i].total_transfered); } // Ligne de séparation printf("%s----------------------------- %s\n", PINK, RESET); } int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "Usage: %s <number_of_threads> <transactions_per_thread>\n", argv[0]); return 1; } int num_threads = atoi(argv[1]); int transactions_per_thread = atoi(argv[2]); int initial_balance = calculate_total_balance(); if (initial_balance < 0) { return 1; } printf(PINK "Solde total initial : %10d€\n" RESET, initial_balance); int fd = open(FILENAME, O_RDONLY); if (fd < 0) { perror("Erreur : Impossible d'ouvrir le fichier"); return 1; } off_t file_size = lseek(fd, 0, SEEK_END); close(fd); int account_count = file_size / ACCOUNT_SIZE; printf(BLUE "Nombre de comptes : %d\n" RESET, account_count); pthread_mutex_init(&file_mutex, NULL); pthread_t threads[num_threads]; ThreadData thread_data[num_threads]; for (int i = 0; i < num_threads; i++) { thread_data[i].transactions = transactions_per_thread; thread_data[i].account_count = account_count; thread_data[i].transactions_done = 0; thread_data[i].transactions_failed = 0; thread_data[i].total_transfered = 0; if (pthread_create(&threads[i], NULL, thread_transactions, &thread_data[i]) != 0) { perror("Erreur : Impossible de créer le thread"); return 1; } } for (int i = 0; i < num_threads; i++) { pthread_join(threads[i], NULL); } pthread_mutex_destroy(&file_mutex); int final_balance = calculate_total_balance(); if (final_balance < 0) { return 1; } printf(PINK "Solde total final : %10d€\n" RESET, final_balance); if (initial_balance != final_balance) { printf(RED "Le solde final est différent du solde initial...\n" RESET); } else { printf(GREEN "Le solde final est identique au solde initial !\n" RESET); } print_statistics(thread_data, num_threads); printf("Tous les threads sont terminés !\n"); return 0; }