diff --git a/System2/RW_problem/Makefile b/System2/RW_problem/Makefile new file mode 100644 index 0000000..7544c8b --- /dev/null +++ b/System2/RW_problem/Makefile @@ -0,0 +1,27 @@ +CCOPTIONS=-g +CC=gcc $(CCOPTIONS) + + +all : lecteurs-redacteurs-mutex lecteurs-redacteurs-moniteur + +clean : + rm lecteurs-redacteurs-mutex lecteurs-redacteurs-moniteur semaphore-moniteur.o tprintf.o + + + +lecteurs-redacteurs-mutex : lecteurs-redacteurs-mutex.c tprintf.o + $(CC) -o lecteurs-redacteurs-mutex lecteurs-redacteurs-mutex.c tprintf.o -lpthread + + +lecteurs-redacteurs-moniteur : lecteurs-redacteurs-moniteur.c tprintf.o + $(CC) -o lecteurs-redacteurs-moniteur lecteurs-redacteurs-moniteur.c tprintf.o -lpthread + + + + + +semaphore-moniteur.o : semaphore-moniteur.c semaphore-moniteur.h + $(CC) -c semaphore-moniteur.c + +tprintf.o : tprintf.c tprintf.h + $(CC) -c tprintf.c diff --git a/System2/RW_problem/TP3.5.2-README.TXT b/System2/RW_problem/TP3.5.2-README.TXT new file mode 100644 index 0000000..5f14d2e --- /dev/null +++ b/System2/RW_problem/TP3.5.2-README.TXT @@ -0,0 +1,213 @@ +********************************** +TP 5 - Moniteurs et semaphores de comptage en pthread + +Partie 2 : Problème des lecteurs/redacteurs + +Duree: 3h + +********************************** + + + + +********************************** +Resolution du probleme des lecteurs redacteurs avec les pthreads +- Partie 2.1: avec des semaphores de comptage uniquement +- Partie 2.2: avec des semaphores mutex uniquement +- Partie 2.3: avec des moniteurs uniquement +********************************** +Contenu: + +* lecteurs-redacteurs-mutex.c : +Le fichier d'implementation des lecteurs redacteurs pour semaphores mutex uniquement (ou semaphores de comptage) qui contient: + lecteur() : fonction principale des threads lecteurs + redacteurs () : fonction principale des threads redacteurs + main() : fonction principale du processus (initialisation, demarrage/terminaison des threads, finalisation) + + +* lecteurs-redacteurs-moniteur.c : +Le fichier d'implementation des lecteurs redacteurs pour les moniteurs uniquement (mutex et conditions) qui contient: + m_prologue_lecteur() et m_epilogue_lecteur(): les points d'entree du moniteur pour les lecteurs + m_prologue_redacteur() et m_epilogue_redacteur(): les points d'entree du moniteur pour les redacteurs + lecteur() : fonction principale des threads lecteurs + redacteurs () : fonction principale des threads redacteurs + main() : fonction principale du processus (initialisation, demarrage/terminaison des threads, finalisation) + + +* semaphore-moniteur.h, semaphore-moniteur.c : +Les fichiers d'implementation des semaphores de comptage avec les moniteurs pthreads (à utiliser dans la partie 2.1) + type_semaphore ; + init_semaphore(); destroy_semaphore(); + P_semaphore(); V_semaphore(); + + +* tprinf.h, tprinf.c : +Les fichiers d'implementation d'un utilitaire tprinf() et tfprintf() +printf() prefixe par "seconds:microsecondes:pid: "), a utiliser pour dater tous les messages + + +* macros-thread.h : +un fichier d'utiliaires (macros C) bien pratiques pour simplifier l'utilisation +des mutex et des conditions pthread (pour les parties mutex 2.2 et moniteur 2.3)) + + +* makefile : +le fichier de construction automatique + make all : construit tous les executables + make clean : efface tous les fichiers compiles + + + +************************************* +************************************* +Sujet de TP : +************************************* +************************************* + + +************************************* +Partie 2.1 : solution a base de semaphores de comptage +fichier: lecteurs-redacteurs-mutex.c +************************************* + +1) commencez par analyser en detail le contenu des differents fichiers + +2) compilez le fichier lecteurs-redacteurs-mutex.c avec le makefile et essayer le programme sans synchronisation. Que ce passe-t-il ? + +3) A l'aide de semaphores de comptage , resolvez le probleme des lecteurs redacteurs. +Proposez 3 solutions differentes: equite, priorite lecteurs, priorite redacteurs +Validez les solutions a l'aide de l'outil JPNS, construisez les reseaux de petri correspondant, et validez-les par simulation. + +4) Implementation des solutions (un fichier different par solution) +Implementez les solutions avec le module semaphores de comptage propose dans semaphore-moniteur.h, semaphore-moniteur.c. +Encadrez chaque operation P() et V() sur les semaphores d'un messsage tprint() afin de tracer/logger l'instant des operations +Modifiez la chaine de lancement des processus lecteurs et redacteurs (macros NBTHREADS et STARTING_CHAIN) +utilisez un debogueur/devermineur supportant le parallelisme des threads (gdb, ddd, ...). + +5) Faites la preuve du bon fonctionnement de la solution priorite redacteur: +- en analysant les messages encadrant les operation P() et V() +- en utilisant les commandes unix ps, top avec les options adaptees aux threads +- en dessinant le chronogramme d'utilisation des operations P() et V() des semaphores de comptage pour l'ensemble des threads lecteurs/redacteurs actives. + + +************************************* +Partie 2.2 : solution a base de semaphores mutex +fichier: lecteurs-redacteurs-mutex.c +************************************* + +3) A l'aide de semaphores mutex pthreads (verrous ou semaphores binaires), resolvez le probleme des lecteurs redacteurs. +Proposez 3 solutions differentes: equite, priorite lecteurs, priorite redacteurs +Validez les solutions a l'aide de l'outil JPNS, construisez les reseaux de petri correspondant, et validez-les par simulation. + +4) Implementation des solutions (un fichier different par solution) +Implementez les solutions avec les mutex pthread (ptread_mutex_* : ptrhread_mutex_t, ptrhread_mutex_init(), ptrhread_mutex_destroy(), ptrhread_mutex_lock(), ptrhread_mutex_unlock() ) +Vous pouvez aussi utiliser les macros du module macros-thread.h : INIT_MUTEX(), DESTROY_MUTEX(), P_MUTEX(), V__MUTEX() +Encadrez chaque operation P() et V() sur les mutex d'un messsage tprint() afin de tracer/logger l'instant des operations +Modifiez la chaine de lancement des processus lecteurs et redacteurs (macros NBTHREADS et STARTING_CHAIN) +utilisez un debogueur/devermineur supportant le parallelisme des threads (gdb, ddd, ...). + +5) Faites la preuve du bon fonctionnement de la solution priorite redacteur: +- en analysant les messages encadrant les operation P() et V() +- en utilisant les commandes unix ps, top avec les options adaptees aux threads +- en dessinant le chronogramme d'utilisation des operations P() et V() sur les mutex pour l'ensemble des threads lecteurs/redacteurs actives. + + +************************************* +Partie 2.3 : solution a base de moniteurs (mutex et conditions) +fichier: lecteurs-redacteurs-moniteur.c +************************************* + +1) commencez par analyser en detail le contenu des differents fichiers + +2) compilez le fichier lecteurs-redacteurs-mutex.c avec le makefile et essayer le programme sans synchronisation. Que ce passe-t-il ? + +3) A l'aide des outils moniteur des pthreads (mutex et conditions), resolvez le probleme des lecteurs redacteurs dans lecteurs-redacteurs-moniteur.c. +proposez 3 solutions differentes: equite, priorite lecteurs, priorite redacteurs. + +4) Implementation des solutions (un fichier different par solution) +Implementez les solutions avec les mutex pthread (ptread_mutex_* : ... ) et les conditions pthread (ptrhread_cond_t, ptrhread_cond_init(), ptrhread_cond_destroy(), ptrhread_cond_wait(), ptrhread_cond_signal() ) +Vous pouvez aussi utiliser les macros du module macros-thread.h : INIT_MUTEX(), DESTROY_MUTEX(), P_MUTEX(), V__MUTEX(), et INIT_COND(), DESTROY_COND(), WAIT_COND(), SIGNAL__COND() +Encadrez chaque operation P(), V(), WAIT(), SIGNAL() sur les mutex et les conditions d'un messsage tprint() afin de tracer/logger l'instant des operations +Modifiez la chaine de lancement des processus lecteurs et redacteurs (macros NBTHREADS et STARTING_CHAIN) +utilisez un debogueur/devermineur supportant le parallelisme des threads (gdb, ddd, ...). + +5) Faites la preuve du bon fonctionnement de la solution priorite redacteur: +- en analysant les messages encadrant les operation P(), V(), WAIT(), SIGNAL() +- en utilisant les commandes unix ps, top avec les options adaptees aux threads +- en dessinant le chronogramme d'utilisation des operations P(), V(), WAIT(), SIGNAL() sur les mutex et les conditions pour l'ensemble des threads lecteurs/redacteurs actives. + + + + +************************************* +ANNEXES +************************************* +1) Déboguer les pthreads avec gdb + +Pour pouvoir controller les threads indépendamment, il suffit d'entrer la séquence de commandes suivante dans gdb: + +# Enable the async interface. +set target-async 1 +# If using the CLI, pagination breaks non-stop. +set pagination off +# Finally, turn it on! +set non-stop on + +Entrer ces commandes dans le fichier ~/.gdbinit pour qu'elles soient prises en compte automatiquement. + +Pour les détails, voir: Non-Stop Mode + + + + +2) Tutoriel débogueur gdb + +voir : Débuggage avec gdb +et Debugging Programs with Multiple Threads + + +commande raccourci effet +run r lance le programme (s'arrête au prochain point d'arrêt) +continue c relance le programme (s'arrête au prochain point d'arrêt) +break xx b xx place un point d'arrêt à la ligne ou à la fonction xx +info breakpoints info breakpoints liste les points d'arrêts +delete d efface les points d'arrêts +next n exécute une instruction (ne rentre pas dans les fonctions) +step s exécute une instruction (rentre potentiellement dans les fonctions) +finish f exécute les instructions jusqu'à la sortie de la fonction +until xx u xx exécute les instructions jusqu'à la ligne xx +watch var w var surveille la variable var +print expr p expr interprète et affiche expr +info threads liste les threads en cours (* devant le thread courant) +thread thread-id thread id devient le thread courant + + + + +3) Débogueur et IDE + +débogueurs seuls : gdb, DDD, Kdb, ... +environnment de developpement (IDE) : eclipse, Kblocks, KDevelop, Code::Blocks, ... + + + + +4) Pour deboguer les pthreads en linux dans netbeans. (préférer eclipse) + +Ceci peut être fait dans netbeans 7.0. Pour installer c/c++ dans netbeans, suivre les étapes suivantes: +- menu "tools/plugins" +- dans settings parametrer le proxy "proxy settings" cache.etu.univ-nantes.fr:3128 +- dans settings, activez les sources "Certified Plugins, Netbeans Distribution, et Plugin Portal +- dans "available plugins" rafraichir le catalogue (update ou refresh), puis installer c/c++ + +Il faut aussi mettre à jour netbeans: +- dans "update" rafraichir le catalogue (update ou refresh), puis bouton update + +La console gdb est accessible dans menu: "window/debugging/debugger console" + +La fenêtre de contrôle des threads dans : "window/debugging/threads" + +Entrer les commandes de la 1ere partie dans le fichier ~/.gdbinit pour qu'elles soient prises en compte automatiquement. + + + diff --git a/System2/RW_problem/lecteurs-redacteurs-moniteur.c b/System2/RW_problem/lecteurs-redacteurs-moniteur.c new file mode 100644 index 0000000..8ddc67f --- /dev/null +++ b/System2/RW_problem/lecteurs-redacteurs-moniteur.c @@ -0,0 +1,229 @@ +/* +* Problème des Lecteurs rédacteurs + * bibliothèque pthread + * Solution avec moniteurs (mutex et conditions) + * + */ + +#include +#include +#include +#include +#include +#include "macros-thread.h" +#include "tprintf.h" + +/* Modifier ici la chaine de lancement des threads */ +#define NBTHREADS 6 +#define STARTING_CHAIN {"w1","r1", "r2", "r3", "w2", "r4"} + + +/* Notions Globales */ + + + + +/* Définition du moniteur: variables d'état, mutex, conditions */ +/* ----------------------------------------------------------- */ + +int nbLecteurs=0; /* Ressource Critique */ +int nbRedacteurs=0; /* Ressource Critique */ + +/* -- A COMPLETER -- */ +/* declarer mutex et conditions pour le moniteur */ + + +/* Points d'entrée du moniteur proteges par E.M.*/ +void m_prologue_lecteur(char *); +void m_epilogue_lecteur(char *); +void m_prologue_redacteur(char *); +void m_epilogue_redacteur(char *); + + +/* Fonctions du moniteur */ + +void m_prologue_lecteur(char * nom) { + + /* -- A COMPLETER -- */ + /* Section à mettre en Exclusion Mutuelle */ + /* par ex: + tprintf("producteur %s demande P(mutex)...\n", nom); + P_MUTEX(mutex); + tprintf("producteur %s obtient P(mutex)...\n", nom); + */ + + /* code en E.M. sur mutex */ + + /* -- A COMPLETER -- */ + /* gerer la synchronisation lecteurs/redacteurs */ + + nbLecteurs ++; + + /* fin d'E.M. */ + + /* -- A COMPLETER -- */ + /* Mettre fin à la section en Exclusion Mutuelle */ +} + + +void m_epilogue_lecteur(char * nom) { + + /* -- A COMPLETER -- */ + /* Section à mettre en Exclusion Mutuelle */ + + /* code en E.M. sur mutex */ + + /* -- A COMPLETER -- */ + /* gerer la synchronisation lecteurs/redacteurs */ + + nbLecteurs --; + + /* fin d'E.M. */ + + /* -- A COMPLETER -- */ + /* Mettre fin à la section en Exclusion Mutuelle */ +} + + + +void m_prologue_redacteur(char * nom) { + + /* -- A COMPLETER -- */ + /* Section à mettre en Exclusion Mutuelle */ + + /* code en E.M. sur mutex */ + + /* -- A COMPLETER -- */ + /* gerer la synchronisation lecteurs/redacteurs */ + + nbRedacteurs=1; + + /* fin d'E.M. */ + + /* -- A COMPLETER -- */ + /* Mettre fin à la section en Exclusion Mutuelle */ +} + + + +void m_epilogue_redacteur(char * nom) { + + /* -- A COMPLETER -- */ + /* Section à mettre en Exclusion Mutuelle */ + + /* code en E.M. sur mutex */ + + /* -- A COMPLETER -- */ + /* gerer la synchronisation lecteurs/redacteurs */ + + nbRedacteurs=0; + + /* fin d'E.M. */ + + /* -- A COMPLETER -- */ + /* Mettre fin à la section en Exclusion Mutuelle */ +} + + +/* fin de definition du moniteur */ +/* ----------------------------- */ + + + +/* Fonction principales des threads "redacteur" */ +void * redacteur(void * arg) { + char * nom = *(char **)arg; + + tprintf("debut thread redacteur %s\n", nom); + + m_prologue_redacteur(nom); + + tprintf("%s ecrit...\n", nom); + sleep(5+rand()%6); + + tprintf("%s etat du tampon partage: nbLecteurs=%i\n", nom, nbLecteurs); + tprintf("%s a fini d ecrire...\n", nom); + + m_epilogue_redacteur(nom); + + tprintf("fin thread redacteur %s\n", nom); + pthread_exit(EXIT_SUCCESS); +} + +/* Fonction principales des threads "lecteur" */ +void * lecteur(void * arg) { + char * nom = *(char **)arg; + + tprintf("debut thread lecteur %s\n", nom); + + m_prologue_lecteur(nom); + + tprintf("%s lit...\n", nom); + sleep(1+rand()%3); + tprintf("%s a fini de lire...\n", nom); + + m_epilogue_lecteur(nom); + + tprintf("fin thread lecteur %s\n", nom); + pthread_exit(EXIT_SUCCESS); +} + +/* Affichage de la chaine de lancement des threads */ +char * chaine_lancement(char * nomsThreads[], char * sep) { + static char starting_chain[3*NBTHREADS+1]=""; + strcat(starting_chain, nomsThreads[0]) ; + for ( int i=1; i +#include +#include +#include + #include +#include "macros-thread.h" +#include "tprintf.h" + +/* Modifier ici la chaine de lancement des threads */ +#define NBTHREADS 6 +#define STARTING_CHAIN {"w1","r1", "r2", "r3", "w2", "r4"} + +/* Notions Globales */ + +#define NBTHREADS 6 + +int nbLecteurs = 0; + +/* -- A COMPLETER -- */ +/* declarer les semaphores mutex */ + + + +/* Fonction principales des threads "redacteur" */ +void * redacteur(void * arg) { + char * nom = *(char **)arg; + + tprintf("debut thread redacteur %s\n", nom); + + /* -- A COMPLETER -- */ + /* gerer la synchronisation lecteurs/redacteurs */ + + tprintf("%s ecrit...\n", nom); + sleep(5+rand()%6); + tprintf("%s : nbLecteurs=%i\n", nom, nbLecteurs); + tprintf("%s a fini d ecrire...\n", nom); + + /* -- A COMPLETER -- */ + /* gerer la synchronisation lecteurs/redacteurs */ + + tprintf("fin thread redacteur %s\n", nom); + pthread_exit(EXIT_SUCCESS); +} + +/* Fonction principales des threads "lecteur" */ +void * lecteur(void * arg) { + char * nom = *(char **)arg; + + tprintf("debut thread lecteur %s\n", nom); + + /* -- A COMPLETER -- */ + /* gerer la synchronisation lecteurs/redacteurs */ + + tprintf("%s lit...\n", nom); + sleep(1+rand()%3); + tprintf("%s a fini de lire...\n", nom); + + /* -- A COMPLETER -- */ + /* gerer la synchronisation lecteurs/redacteurs */ + + tprintf("fin thread lecteur %s\n", nom); + pthread_exit(EXIT_SUCCESS); +} + +/* Affichage de la chaine de lancement des threads */ +char * chaine_lancement(char * nomsThreads[], char * sep) { + static char starting_chain[3*NBTHREADS+1]=""; + strcat(starting_chain, nomsThreads[0]) ; + for ( int i=1; i +#include +#include +#include +#include "tprintf.h" +#include "macros-thread.h" +#include "semaphore-moniteur.h" + + +/* Définition du moniteur */ +/* ---------------------- */ + + +/* Points d'entrée */ +/* Fonctions du moniteur */ +/* seulement 2 fonctions en exclusion mutuelle : P_semaphore() et V_semaphore() */ +/* Attention, les autres fonction sne sont pas protegees */ + + +void init_semaphore(type_semaphore * sem, int val){ + + /* implementer l'initialisation de tous les champs + de l'enregistrement type-semaphore: mutex, attenteFifo, nbAttente, value + utiliser INIT_MUTEX, et INIT_COND + */ + INIT_MUTEX(sem->mutex); + INIT_COND(sem->attenteFifo); + sem->nbAttente=0; + sem->value=val; + return; +} + + +void P_semaphore(type_semaphore * sem){ + + /* implementer l'operateur semaphore P(sem) en exclusion mutuelle + modifie les champs de l'enregistrement type-semaphore: nbAttente, value + utiliser P_MUTEX, V_MUTEX et WAIT_COND + */ + P_MUTEX(sem->mutex); + sem->value--; + if ( sem->value < 0 ) { + sem->nbAttente++; + WAIT_COND(sem->attenteFifo,sem->mutex); + sem->nbAttente--; + } + V_MUTEX(sem->mutex); + return; +} + + +void V_semaphore(type_semaphore * sem){ + + /* implementer l'operateur semaphore V(sem) en exclusion mutuelle + modifie les champs de l'enregistrement type-semaphore: value + utiliser P_MUTEX, V_MUTEX et SIGNAL_COND + */ + P_MUTEX(sem->mutex); + sem->value++; + if ( sem->value <= 0 ) { + SIGNAL_COND(sem->attenteFifo); + } + V_MUTEX(sem->mutex); + return; +} + + +void destroy_semaphore(type_semaphore * sem){ + + /* implementer la destruction du semaphore + modifie les champs de l'enregistrement type-semaphore: nbAttente, value + */ + DESTROY_MUTEX(sem->mutex); + DESTROY_COND(sem->attenteFifo); + sem->nbAttente=0; + sem->value=0; + return; +} + + + +int value_semaphore(type_semaphore * sem){ + + /* implementer la lecture non protegee de la valeur du semaphore: champs value */ + + return sem->value; +} + + +int estVideFifo_semaphore(type_semaphore * sem){ + + /* implementer l'acces au nombre de processus en attente en liste Fifo semaphore: champs nbAttente */ + + return sem->nbAttente==0; +} + + diff --git a/System2/RW_problem/semaphore-moniteur.h b/System2/RW_problem/semaphore-moniteur.h new file mode 100644 index 0000000..13f9788 --- /dev/null +++ b/System2/RW_problem/semaphore-moniteur.h @@ -0,0 +1,33 @@ +/* + * Implementation de semaphore de comptage par moniteur + * bibliothèque pthread + * Moniteur = semaphores binaires(mutex) + conditions + * + */ + +#ifndef _SEM_ +#define _SEM_ + +#include + +/* Notions Globales */ + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t attenteFifo; + int nbAttente; + int value; +} type_semaphore; + +void init_semaphore(type_semaphore * sem,int val); +void P_semaphore(type_semaphore * sem); +void V_semaphore(type_semaphore * sem); +void destroy_semaphore(type_semaphore * sem); +int value_semaphore(type_semaphore * sem); +int estVideFifo_semaphore(type_semaphore * sem); + +#endif + + + + diff --git a/System2/RW_problem/tprintf.c b/System2/RW_problem/tprintf.c new file mode 100644 index 0000000..5e883e2 --- /dev/null +++ b/System2/RW_problem/tprintf.c @@ -0,0 +1,48 @@ +/* Utilitaire printf estampille : a reutiliser ... + print et fprintf prefixes par "seconds:microsecondes:pid: " ou "seconds:microsecondes:pid:tid: " +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "tprintf.h" + + + +/* printf estampille : a reutiliser ... */ + +int tprintf(const char * message, ... ) { + va_list liste; + char chaine [1000]; + struct timeval t; + int pid = getpid(); + int tid = (int) syscall(SYS_gettid); + va_start(liste, message); + gettimeofday( &t, NULL); + vsprintf(chaine, message, liste); + if ( pid == tid ) + return printf("%ld:%ld:%i: %s", t.tv_sec, t.tv_usec, pid, chaine ); + else + return printf("%ld:%ld:%i:%i %s", t.tv_sec, t.tv_usec, pid, tid, chaine ); +} + +int tfprintf(FILE * stream, const char * message, ... ) { + va_list liste; + char chaine [1000]; + struct timeval t; + int pid = getpid(); + int tid = (int) syscall(SYS_gettid); + va_start(liste, message); + gettimeofday( &t, NULL); + vsprintf(chaine, message, liste); + if ( pid == tid ) + return fprintf(stream, "%ld:%ld:%i: %s", t.tv_sec, t.tv_usec, pid, chaine ); + else + return fprintf(stream, "%ld:%ld:%i:%i %s", t.tv_sec, t.tv_usec, pid, tid, chaine ); +} + diff --git a/System2/RW_problem/tprintf.h b/System2/RW_problem/tprintf.h new file mode 100644 index 0000000..e94b450 --- /dev/null +++ b/System2/RW_problem/tprintf.h @@ -0,0 +1,11 @@ +/* Utilitaire printf estampille : a reutiliser ... + print et fprintf prefixes par "seconds:microsecondes:pid: " ou "seconds:microsecondes:pid:tid: " +*/ + +#include + + +/* printf estampille : a reutiliser ... */ +int tprintf( const char *, ... ); +int tfprintf(FILE * stream, const char * message, ... ); +