Ajouts de thread + modifications
This commit is contained in:
parent
5a8540b2da
commit
d6de89853a
Secured
SecuredThread
Unsecured
@ -2,7 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <string.h>
|
||||
|
||||
|
13
SecuredThread/Makefile
Normal file
13
SecuredThread/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
# Nom de l'exécutable
|
||||
TARGET = secured_transaction_threads
|
||||
|
||||
# Fichier source
|
||||
SRC = secured_transaction_threads.c
|
||||
|
||||
# Règle par défaut : compilation et lien
|
||||
all:
|
||||
gcc $(SRC) -o $(TARGET)
|
||||
|
||||
# Nettoyage des fichiers générés
|
||||
clean:
|
||||
rm -f $(TARGET)
|
137
SecuredThread/README.md
Normal file
137
SecuredThread/README.md
Normal file
@ -0,0 +1,137 @@
|
||||
# 🔒 Transactions Sécurisées avec Threads
|
||||
|
||||
Ce programme simule des transactions bancaires concurrentes en utilisant des **threads**, une approche plus efficace et légère que les processus. Les threads exécutent des transactions entre comptes bancaires, tout en partageant les ressources de manière optimale grâce à des mécanismes de verrouillage qui garantissent l'intégrité des données.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Description du Programme
|
||||
|
||||
Le programme utilise des threads pour gérer plusieurs transactions simultanées entre comptes bancaires stockés dans un fichier de base de données. Contrairement à une version basée sur des processus, cette approche utilise un espace mémoire partagé, réduisant les coûts de communication et augmentant la performance.
|
||||
|
||||
### Fonctionnalités principales :
|
||||
1. **Gestion multithreadée des transactions :**
|
||||
Chaque thread effectue un certain nombre de transactions aléatoires entre les comptes bancaires.
|
||||
|
||||
2. **Synchronisation avec Mutex :**
|
||||
Des verrous sont utilisés pour garantir des accès sécurisés au fichier contenant les comptes, empêchant les corruptions de données.
|
||||
|
||||
3. **Optimisation des ressources :**
|
||||
Les threads partagent la mémoire et les ressources du processus parent, réduisant les coûts liés à la création et à la gestion des entités concurrentes.
|
||||
|
||||
4. **Calcul du solde total :**
|
||||
Le programme vérifie l'intégrité des données en calculant le solde total avant et après les transactions.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Compilation et Exécution
|
||||
|
||||
### Compilation
|
||||
Utilisez le fichier `Makefile` pour compiler le programme :
|
||||
```bash
|
||||
make
|
||||
```
|
||||
Cela génère un exécutable nommé `secured_transaction_threads`.
|
||||
|
||||
### Exécution
|
||||
Exécutez le programme en spécifiant :
|
||||
- Le nombre de threads à lancer.
|
||||
- Le nombre de transactions par thread.
|
||||
|
||||
Exemple :
|
||||
```bash
|
||||
./secured_transaction_threads 4 10
|
||||
```
|
||||
Ici, 4 threads seront créés, chacun effectuant 10 transactions.
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Pourquoi utiliser des Threads ?
|
||||
|
||||
### **1. Partage de Mémoire :**
|
||||
- Les threads partagent l'espace mémoire du processus parent, ce qui permet un accès rapide et direct aux données.
|
||||
- Dans cette application, tous les threads peuvent accéder et modifier les comptes bancaires sans mécanismes complexes de communication inter-processus.
|
||||
|
||||
### **2. Performance Optimisée :**
|
||||
- Les threads sont plus légers que les processus. La création d'un thread est moins coûteuse en temps et en ressources.
|
||||
- La commutation de contexte entre threads est plus rapide que celle entre processus, ce qui améliore les performances globales.
|
||||
|
||||
### **3. Synchronisation Facile :**
|
||||
- Grâce aux primitives comme les **mutex**, les threads peuvent synchroniser leurs accès aux ressources partagées de manière efficace.
|
||||
- Ici, un mutex est utilisé pour s'assurer qu'un seul thread à la fois modifie le fichier des comptes bancaires.
|
||||
|
||||
### **4. Adapté au Parallélisme :**
|
||||
- Les threads permettent de tirer parti des architectures multicœurs, ce qui accélère les transactions simultanées.
|
||||
|
||||
---
|
||||
|
||||
## 🛑 Problèmes Résolus
|
||||
### **1. Incohérences de Données :**
|
||||
Les mécanismes de verrouillage garantissent que chaque transaction est exécutée de manière atomique. Cela empêche les conflits d'accès entre plusieurs threads.
|
||||
|
||||
### **2. Solde Final Correct :**
|
||||
Grâce à la synchronisation, le solde total des comptes reste cohérent avant et après les transactions.
|
||||
|
||||
### **3. Gestion des Transactions :**
|
||||
Chaque transaction est complètement exécutée avant qu'une autre ne puisse accéder aux mêmes données.
|
||||
|
||||
---
|
||||
|
||||
## 📜 Exemple de Résultat
|
||||
|
||||
### Avant l'exécution
|
||||
Le fichier `accounts.db` contient :
|
||||
```plaintext
|
||||
...
|
||||
Diana 7145
|
||||
Diego 8494
|
||||
Dominic 4487
|
||||
Dylan 1157
|
||||
Easton 429
|
||||
Eden 5737
|
||||
Edward 3671
|
||||
Elaina 4904
|
||||
...
|
||||
```
|
||||
|
||||
### Compilation et exécution
|
||||
On compile le programme avec :
|
||||
```bash
|
||||
make
|
||||
```
|
||||
ou
|
||||
```bash
|
||||
gcc secured_transaction_threads.c -o secured_transaction_threads -pthread
|
||||
```
|
||||
Puis, on exécute :
|
||||
```bash
|
||||
./secured_transaction_threads 4 10
|
||||
```
|
||||
|
||||
### Après l'exécution
|
||||
Voici une sortie typique du programme :
|
||||
|
||||
```plaintext
|
||||
Solde total initial : 400000€
|
||||
...
|
||||
Transaction : Alivia -> Kaiden : 14€
|
||||
Transaction : Arianna -> Barrett : 3€
|
||||
Transaction : Rosalie -> Connor : 1€
|
||||
Transaction : Sara -> Arthur : 190€
|
||||
Transaction : Jude -> Sadie : 41€
|
||||
...
|
||||
Solde total final : 400000€
|
||||
Tout est terminé sans incohérences !
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Points Forts de cette Version
|
||||
|
||||
1. **Sécurité des Données :**
|
||||
Les mécanismes de verrouillage évitent toute corruption des données.
|
||||
|
||||
2. **Efficacité :**
|
||||
L'utilisation de threads optimise les performances par rapport à une version basée sur des processus.
|
||||
|
||||
3. **Simplicité :**
|
||||
Les threads partagent directement les ressources, éliminant le besoin de communication inter-processus.
|
224
SecuredThread/secured_transaction_threads.c
Normal file
224
SecuredThread/secured_transaction_threads.c
Normal file
@ -0,0 +1,224 @@
|
||||
#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;
|
||||
}
|
@ -10,6 +10,13 @@
|
||||
#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"
|
||||
|
||||
// Fonction pour lire un compte dans le fichier avec verrouillage
|
||||
void read_account(int fd, int index, char *name, int *balance) {
|
||||
char buffer[ACCOUNT_SIZE];
|
||||
@ -64,9 +71,9 @@ void perform_transaction(int fd, int account_count) {
|
||||
write_account(fd, from_idx, from_name, from_balance);
|
||||
write_account(fd, to_idx, to_name, to_balance);
|
||||
|
||||
printf("Transaction : %s -> %s : %d€\n", from_name, to_name, transfer_amount);
|
||||
printf(GREEN "Transaction : %s -> %s : %d€\n" RESET, from_name, to_name, transfer_amount);
|
||||
} else {
|
||||
printf("Transaction annulée : Fonds insufisants %s\n", from_name);
|
||||
printf(RED "Transaction annulée : Fonds insufisants %s\n" RESET, from_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user