Problème des lecteurs et des écrivains
Transcription
Problème des lecteurs et des écrivains
Systèmes d'exploitation Jean-Marie Beaulieu LABORATOIRE IFT-10544 Z1 et W E06 no 3 Problème des lecteurs et des écrivains Plusieurs lecteurs peuvent accéder au fichier simultanément. Les écrivains accèdent au fichier un à la fois. Si un lecteur a déjà accès au fichier, tout autre lecteur peut y accéder immédiatement. Si un écrivain a accès au fichier, les autres lecteurs ou écrivains doivent attendre qu'il ait fini. Un écrivain peut accéder au fichier seulement s'il n'y a pas de lecteur. Ce problème est présenté à la section 7.5.2 des notes de cours. La solution proposée avec sémaphores est contenue dans le fichier "/home/cours/ift-10544/e06/lab3/lec_cas1.cpp". Notez que dans cet algorithme, quand un écrivain fait wrt.signal(), il amorce l'exécution soit des lecteurs ou de l'un des écrivains en attente. Partie 1: Vous devez examiner l'algorithme correspondant au problème présenté dans le texte (section 7.5.2) et l'essayez sur deux séquences de lecteur-écrivain (déjà écrit dans lec_cas1.cpp, voir "Détails de programmation"). Le programme produit un diagramme indiquant pour chaque lecteur ou écrivain 1) le temps de création (demande d'accès à sa section critique), 2) le début d'exécution dans sa région critique et 3) la fin d'exécution dans sa région critique. À partir de ces diagrammes, commentez la synchronisation des lecteurs-écrivains. Partie 2: Modifiez le programme pour donner la priorité aux lecteurs sur les écrivains (encore plus de priorité). Dans l'algorithme ci-dessus, quand un écrivain fait wrt.signal(), il amorce l'exécution soit des lecteurs ou de l'un des écrivains en attente. Modifiez le programme pour que l'écrivain qui fait wrt.signal() amorce nécessairement les lecteurs s'il y en a en attente. Obtenez les diagrammes pour les deux séquences possibles et commentez-les. Partie 3: Modifiez le programme pour donner plus de priorité aux écrivains. Dans la partie 1, quand un écrivain termine l'utilisation du fichier, il peut être suivi soit par un autre écrivain soit par un ou plusieurs lecteurs. Modifiez le programme pour que lorsqu'un écrivain relâche le fichier qu'il soit nécessairement suivi par un autre écrivain s'il y a un ou des écrivains en attente. Notez que si un lecteur a déjà accès au fichier, il faut toujours permettre aux autres lecteurs d'y accéder même s'il y a un écrivain en attente (la solution dans le livre de Stallings ne convient pas ici). Obtenez les diagrammes pour les deux séquences possibles et commentez-les. Remarquez que les deux séquences disponibles ne sont que des exemples. Vos programmes devraient fonctionner pour n'importe quelle séquence. Il est également important de ne pas utiliser de boucle d'attente active. Le rapport (dans un fichier RTF) – La date de remise est 20 juin 23h00 par intranet (pixel) Pour chacune des parties, donnez : a) une brève description de la solution et le "listing" du programme (facultatif pour la partie 1). b) pour chacune des deux séquences, le résultat obtenu et sa justification (expliquez pourquoi ce résultat est conforme à ce qui est demandé en faisant référence au graphe; par exemple, "le lecteur X a accès au fichier seulement au temps T parce que …"). Utilisez une police de caractère fixe (courrier) pour une meilleure présentation du graphe. _________________________ Note: Vous pouvez récupérer ce fichier de "/home/cours/ift-10544/e06/lab3/labo-3-e06.rtf". Détails de programmation: Fichier lec_cas1.cpp Copiez dans votre répertoire le contenu du répertoire "/home/cours/ift-10544/e06/lab3". Le fichier lec_x.cpp contient une structure de base (coquille) qu'il faut compléter. Le fichier lec_cas1.cpp est la solution correspondant à la partie 1. La colonne ci-contre présente cette solution. Les régions encadrées montrent les endroits où vous pouvez ajouter et modifier le code. Le programme génère 9 processus lecteurs ou écrivains. Les résultats en sortie indiquent les temps 1) de création, 2) de début d'accès au fichier et 3) de fin d'accès de chaque processus. // // probleme des lecteurs / ecrivains // //================================================= // inclusion du simulateur concur // du moniteur Profil // du programme principal et des fonctions-processus # include "le_main.hpp" //================================================= // Definition des semaphores et variables globales //================================================= int readcount = 0 ; Semaphore mutex( 1 ); Semaphore wrt( 1 ); La commande ./g++_concur lec_x permet de compiler le programme (remplacez "x" par la valeur requise) et la commande "./lec_x 1" ou "./lec_x 2" va exécuter le programme avec la séquence 1 ou 2. CONCUR est un simulateur de processus concurrent. Dans Linux, on utilise les fonctions de création et de gestion de Pthreads. Dans le programme "lec_cas1.cpp" qui suit, les régions encadrées montrent les endroits où vous pouvez ajouter et modifier le code. Au début du programme, nous avons une inclusion du fichier "le_main.hpp". Ce fichier contient le programme principal (main) qui permet de générer deux séquences de processus. Il faut exécuter le programme avec le paramètre "1" ou "2" pour choisir la séquence désirée (./lec_x 1 ou ./lec_x 2). Remarquez que les deux séquences disponibles ne sont que des exemples. Vos programmes devraient fonctionner pour n'importe quelle séquence. //================================================= // fonction appele par les processus lecteurs/ecrivains // pour definir leurs comportements //================================================= void Lecteur( int no, int duree ) { mutex.wait( ); readcount = readcount + 1; if ( readcount == 1 ) wrt.wait( ) ; mutex.signal( ); // TRAITEMENT LECTEUR // correspond a l'acces en lecture au fichier TRAITEMENT( no, duree ); mutex.wait( ); readcount = readcount - 1; if ( readcount == 0 ) wrt.signal( ); mutex.signal( ); } void Ecrivain( int no, int duree ) { wrt.wait( ); Au début du programme, il faut définir les variables globales et les sémaphores. L'exemple montre comment initialiser un sémaphore. Les deux opérations sur les sémaphores sont "wait()" et "signal()". // TRAITEMENT ECRIVAIN // correspond a l'acces en ecriture au fichier TRAITEMENT( no, duree ); wrt.signal( ); } Pour faciliter l'interprétation de ces résultats, le programme produit un graphique (diagramme) (voir exemple qui suit) en fonction du temps. Chaque colonne correspond à un processus. Le symbole "---" indique que le processus est en attente pour accéder au fichier. Les symboles "Lec" et Ecr" indiquent que le processus a accès au fichier. L'espace blanc au début indique que le processus n'est pas encore créé. La fonction "TRAITEMENT" représente l'accès au fichier. Le paramètre "durée" représente le temps pendant lequel le processus utilisera le fichier. Vous devez donc placer des instructions avant et après l'appel à "TRAITEMENT" pour assurer le bon comportement des processus. Le code contenu dans le fichier "le_main.hpp" permet la production du graphique. Il permet également la création d'une séquence de processus. Le simulateur concur est composé de plusieurs fichiers. Sur Linux, on utilise le compilateur "g++". Le fichier script "g++_concur" permet de compiler facilement un programme utilisant le simulateur. Le script doit avoir les droits d'accès en exécution ("chmod ugo+x g++_concur"). Le programme doit avoir une extension ".cpp". On compile avec ./g++_concur nom-prog où le nom du programme ("nom-prog") est sans extension. On obtient un fichier exécutable appelé "nom-prog". Ce script a besoin de plusieurs fichiers d'en-tête et de fichiers objet "*.o". Au besoin, vous pouvez utiliser le script "g++_set_concur" pour construire les 3 fichiers objet nécessaires à partir des fichiers "*.cpp". Pendant le délai de création ¼ sortie " " blanc Après la création ¼ "---" Pendant Traitement( ) ¼ "Lec" ou "Ecr" Après Traitement( ) ¼ " " blanc temps 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 1 Lec Lec Lec Lec Lec Lec 2 Lec Lec Lec Lec Lec Lec 3 ----------Ecr Ecr Ecr Ecr Ecr Ecr Ecr 4 ------------------Lec Lec Lec Lec Lec Lec 5 --------------------------Ecr Ecr Ecr Ecr Ecr Ecr 6 ----------------------Lec Lec Lec Lec Lec 7 ------------------------------Ecr Ecr Ecr Ecr Ecr Ecr 8 9 --------------Lec Lec Lec Lec Lec ------Lec Lec Lec Lec Lec note: cette sortie ne correspond à aucune des parties 1, 2 ou 3. Jean-Marie Beaulieu 5 juin 2006