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