|
|
TELECOM & Management SudParis
TELECOM SudParis 2ème
année
TP Noté CSC4508/M2 du 16/05/08
(Corrigés)
Modalités
Durée : 3 heures
Tous documents autorisés.
Les questions 1, 2, 3 et 4 sont indépendantes les
unes
des autres. Aussi, n'hésitez pas à lire tout le
sujet avant de commencer pour déterminer l'ordre dans lequel
vous souhaitez traiter les questions.
Le barème est donné à titre indicatif
des poids
entre les différentes questions.
La « livraison » de votre travail
en fin de TP
noté se fera par remise de votre copie à
l'enseignant et
par
remontée sous Moodle (rubrique « TP
noté de 3
heures ») du fichier d'extension tgz
constitué de
la manière suivante :
cd votreRepertoireDeTravailPourCSC4508M2 tar cvfz $USER.tgz TPNote2008
Préparation
cd votreRepertoireDeTravailPourCSC4508M2 cp ~simatic/Cours/CSC4508/tPNote2008.tgz . tar xvfz tPNote2008.tgz cd TPNote2008
Question 1 : Bugs non reproductibles ? (5
points)
Pour chacune des questions ci-dessous, répondez sur votre
copie
ou
bien dans le fichier Q1/reponse1.txt (dans ce
dernier
cas, indiquez sur votre
copie « Réponse dans Q1/reponse1.txt »
).
Question 1-1 : Premier programme (3 points)
Expliquez brièvement ce que fait le programme correspondant
au
fichier Q1/prog1.c
/***********/
/* prog1.c */
/***********/
#include
<stdlib.h>
#include
<stdio.h>
#include
<unistd.h>
#include
<sys/stat.h>
#include
<fcntl.h>
#include
<string.h>
#define NOMFIC
"/tmp/ficPourProg1"
#define
NBENREG 1000
#define
ENREGFORMATE "Enregistrement #1234567\n"
int main() {
int
i;
FILE *ficW;
int
ficR;
char buf[256];
ficW = fopen(NOMFIC, "w");
for
(i=0 ; i<NBENREG; i++){
fprintf(ficW, "Enregistrement #%7d\n", i);
}
fclose(ficW);
ficR = open(NOMFIC, O_RDONLY);
for
(i=0 ; i<NBENREG; i++){
read(ficR,
(void*)buf,
strlen(ENREGFORMATE));
buf[strlen(ENREGFORMATE)-1] = '\0';
printf("Chaine lue : \"%s\"\n", buf);
}
close(ficR);
return EXIT_SUCCESS;
}
---beginCorr
barème : 0,5 point
Ce programme crée un fichier /tmp/ficPourProg1
dans lequel il écrit 1000 enregistrements sous la forme
« Enregistrement
# 985 ».
Il ferme ensuite ce
fichier avant
de le
réouvrir en lecture afin de lire ces différents
enregistrements.
---endCorr
Ce programme fonctionne parfaitement, sauf sur
la machine ayant pour hostname
« assous »
où il se met à répéter une
certaine ligne (la ligne répétée
changeant à
chaque nouvelle exécution du programme). Par exemple, lors
d'une
exécution, on peut avoir l'affichage :
Chaine lue : "Enregistrement
# 983"
Chaine lue :
"Enregistrement # 984"
Chaine lue :
"Enregistrement # 985"
Chaine lue :
"Enregistrement # 985"
Chaine lue :
"Enregistrement # 985"
Chaine lue :
"Enregistrement # 985"
Chaine lue :
"Enregistrement # 985"
cette ligne « Chaine
lue : "Enregistrement # 985" »
étant répétée 15 fois au
total.
Modifiez le fichier Q1/prog1.c pour
que toutes les éventuelles erreurs à
l'exécution puissent être
détectées (en cas d'erreur
détectée, on arrêtera
immédiatement
l'exécution du programme).
---beginCorr
barème : 0,25 point par vérification
d'erreurs correcte, soit
1,5 point au total.
prog1.corrige.c
---endCorr
Cette nouvelle version du programme est exécutée
sur la machine « assous ».
On
obtient le message d'erreur suivant :
Erreur 'No space left on
device' lors ecriture fichier /tmp/ficPourProg1
Expliquez
cette erreur, puis décrivez une expérience
permettant de
reproduire sur n'importe quelle machine le problème
observé
sur la
machine « assous ».
NB : on ne demande pas de réaliser cette
expérience.
---beginCorr
barème :
- explication de l'erreur : 0,5 point ;
- expérience : 0,5 point ;
Le problème vient du fait que la partition disque de la
machine « assous »
dans
laquelle est écrit le fichier /tmp/ficPourProg1
est saturée. Donc, pour reproduire le problème
sur n'importe quel
machine, il suffit de saturer la partition disque hébergeant
le
répertoire /tmp
avant de lancer le programme.
---endCorr
Question 1-2 : Deuxième programme (2 points)
Expliquez brièvement ce que fait le programme correspondant
au fichier Q1/prog2.c
/***********/
/* prog2.c */
/***********/
#include
<stdlib.h>
#include
<sys/ipc.h>
#include
<sys/shm.h>
#include
<string.h>
#define SHMKEY
30
#define TAILLE
1<<26
int main() {
char *shm_adr;
int
shm_id;
shm_id = shmget(SHMKEY, TAILLE, 0700|IPC_CREAT);
shm_adr = shmat(shm_id, 0, 0);
memset(shm_adr, 0, TAILLE);
return EXIT_SUCCESS;
}
Ce programme fonctionne parfaitement, sauf sur
la machine ayant pour hostname
« oiserie »
où il s'arrête avec le message suivant :
Erreur de segmentation (core
dumped)
Modifiez le fichier Q1/prog2.c pour
que toutes les éventuelles erreurs à
l'exécution puissent être
détectées (en cas d'erreur
détectée, on arrêtera
immédiatement
l'exécution du programme).
Cette nouvelle version du programme est exécutée
sur la machine « oiserie ».
On
obtient le message d'erreur suivant :
shmget: Invalid argument
Expliquez cette erreur (barème : 0,5 point), puis
décrivez une expérience permettant de
reproduire sur n'importe quelle machine le problème
observé
sur la
machine « oiserie »
(barème : 0,5 point).
NB : on ne demande pas de réaliser cette
expérience.
---beginCorr
Ce programme crée une zone de mémoire
partagée de 64 Mo dont
il initialise tous les octets à zéro.
Voici le programme corrigé : prog2.corrige.c
Pour reproduire cette erreur sur n'importe quelle machine, il faut
saturer la mémoire du système avant de lancer ce
programme.
barème :
- objectif du programme : 0,5 point ;
- ajout du code de correction : 0,25 point par
contrôle, soit 0,5 point au total ;
- explication de l'erreur : 0,5 point ;
- proposition d'expérience : 0,5 point ;
---endCorr
Question 2 : Rendez-vous conditionnel (5
points)
Le
commentaire du transparent 3.3.2 (rendez-vous entre deux processus) du
cours « Synchronisation entre
processus » présente un algorithme pour
un
rendez-vous entre N processus à l'aide de
sémaphores P et V.
Écrire, à l'aide des
opérations pthread_mutex_lock
et pthread_mutex_unlock d'objets mutex thread
et des opérations pthread_cond_wait
et
pthread_cond_broadcast (NB :
on n'utilisera pas l'opération pthread_cond_signal )
d'objets condition,
l'algorithme d'une procédure
rdv
permettant de programmer un rendez-vous entre N threads.
Rappelons que, quand un thread
appelle cette procédure rdv
:
- s'il est le 1er, le 2ème...
ou le N-1ème
à l'appeler, ce thread
se retrouve bloqué, en attente, dans cette
procédure ;
- s'il est le Nème
à l'appeler, ce
thread
débloque les N-1 autres threads
en attente et poursuit son exécution.
NB : Pour simplifier l'algorithme de rdv, on suppose
que chaque thread
n'appelle rdv
qu'une seule fois.
Pour cette question, répondez sur votre
copie
ou
bien dans le fichier Q2/reponse2.txt (dans ce
dernier
cas, indiquez sur votre
copie « Réponse dans Q2/reponse2.txt »).
---beginCorr
barème :
- toutes les variables sont là : 1 (-
0,33
par
variable manquante) ;
- la variable nbArrivesAuRDV est
correctement
initialisée
: 1 ;
- 3 points pour l'algorithme
Variables globales ================== // Nombre de processus arrivés au RDV int nbArrivesAuRDV = 0
// Mutex et condition pthread_mutex_t mutex pthread_cond_t condToutLeMondeEstLa
Algorithme de rdv ================= pthread_mutex_lock(&mutex) nbArrivesAuRDV = nbArrivesAuRDV + 1 si nbArrivesAuRDV < N alors repeter pthread_cond_wait(&condToutLeMondeEstLa, &mutex) jusqu'à nbArrivesAuRDV == N sinon pthread_cond_broadcast(toutLeMondeEstLa) finsi pthread_mutex_unlock(&mutex)
NB : supposons qu'un thread
appelle 2 fois consécutivement rdv.
Dans ce cas, le dernier thread
arrivé dans le premier appel à rdv
(donc, celui qui réveille
tous les autres) peut immédiatement après appeler
à nouveau rdv
avant que
les
autres n'aient effectivement été
réveillés. La valeur de nbArrivesAuRDV
ne
représentera donc plus le nombre de processus en attente
lors du
premier appel à rdv,
ce qui entraînera des dysfonctionnements
ultérieurs.
---endCorr
Question 3 : Expériences autour d'un serveur
Web (7
points + 2 points de bonus)
---beginCorr
Le corrigé des différentes sous-questions de
cette question 3 ne sera mis à disposition que quand
l'exercice Hors Présentiel numéro 2 aura
été rendu par les étudiants.
---endCorr
Le
code présent dans le répertoire Q3-1
contient un serveur Web
très
simplifié : quand on l'interroge, ce serveur se contente de
renvoyer
une page Web contenant le nombre de fois qu'on l'a interrogé
(et donc
qu'il a répondu).
---beginCorr
Pour information, le code de ce serveur est une adaptation du code
tiré du chapitre 11 du livre Advanced Linux Programming
(http://www.advancedlinuxprogramming.com/).
---endCorr
Avant de rentrer dans le vif du sujet, faites fonctionner ce serveur :
- dans
un terminal, positionnez-vous dans le répertoire Q3-1, tapez make pour
compiler, puis server
pour lancer l'exécution du serveur ;
NB :
- par
défaut, le serveur se met en attente sur le port 8080 ;
- si vous
souhaitez qu'il utilise un autre numéro de port, tapez la
commande :
server -p numeroPort
- si vous obtenez l'erreur « ./server: erreur 'Address
already in use' ==> vous devez relancer le serveur en
précisant un autre numéro de port avec la
commande 'server -p numeroDePort' »,
alors relancez le serveur en précisant un autre
numéro de
port que le numéro que vous venez d'utiliser ;
- dans un navigateur Web, tapez l'adresse
http://localhost:8080
(ou un autre numéro de port, si vous avez
démarré
votre serveur avec un autre numéro de port) ;
- le navigateur Web affiche : « compteurReponse = 1 »
(le serveur indique qu'il a été
interrogé une fois et donc qu'il a
répondu une fois) ;
- si
vous cliquez plusieurs fois sur le bouton
« Rafraîchir / Actualiser la
page courante » du navigateur, votre navigateur
interroge à chaque fois
le serveur qui renvoie donc successivement : « compteurReponse
= 2 », « compteurReponse
= 3 »... ;
- arrêtez votre serveur (à l'aide
des touches Control
et C).
Pour fonctionner, ce serveur utilise 4 modules : codeEtudiant.c,
common.c,
main.c
et server.c.
Mais, dans les questions suivantes, vous serez amené
à
modifier seulement codeEtudiant.c
(c'est pourquoi c'est le seul module sur lequel vous avez les droits en
écriture). En effet, ce module héberge 3
fonctions qui interagissent
avec le reste du code :
- la procédure init
réalise toutes les
initialisations de votre module avant que le serveur web ne se mette en
attente de requêtes Web. Ainsi, dans le code livré
dans le répertoire Q3-1,
cette
procédure initialise à 0
une variable appelée compteurReponse
;
- la
procédure gestion_connexion_entrante
est appelée lorsque le serveur web
reçoit une requête Web. Cette procédure
(qui est appelée avec un
paramètre connexion_fd)
est chargée de confier à un thread
la responsabilité d'appeler la
procédure
handle_connection
(définie dans un des autres modules que vous n'avez pas
à modifier)
avec la valeur de ce paramètre connexion_fd.
Ainsi,
dans le code livré dans le répertoire Q3-1, cette
procédure crée un
thread thread_gestion_connexion_entrante
(avec en paramètre la
valeur de connexion_fd).
Et ce thread
se charge, quand il
prend la main, d'appeler handle_connection
avec la valeur
de connexion_fd
;
- la fonction gestion_compteurReponse
est
chargée d'effectuer les traitements liés
à la variable compteurReponse
lorsque le serveur répond à une requête
HTTP. Elle modifie la valeur de
compteurReponse,
puis retourne la valeur
courante de compteurReponse.
Ainsi, dans le code livré dans le répertoire Q3-1, cette
fonction incrémente compteurReponse,
puis retourne sa valeur.
Les questions Q3-1 à Q3-4 sont destinées
à
améliorer le fonctionnement de ce serveur. Noter que seront
évalués :
- la clarté du code,
- le fait que le code compile (sans warning),
- le fait que le retour de chaque appel
système, s'il y en a un,
est testé avec appel à
perror() ,
puis exit(EXIT_FAILURE)
en cas de problème détecté,
- le fait que le code répond correctement
à la question posée.
Question 3-1 : Empêcher les pertes
d'incrémentation de compteurReponse
(2 points)
La
variable compteurReponse
peut être manipulée par plusieurs threads
travaillant en
parallèle. On peut donc potentiellement perdre des
incrémentations de
cette variable. Pour tenter de l'observer, utilisons ab, l'outil
de benchmark d'Apache,
qui permet d'envoyer un certain nombre de
requêtes vers un serveur, dans un laps de temps
très court. Effectuez les opérations
suivantes :
- dans un terminal, démarrez le serveur ;
- dans
un autre terminal, tapez la commande :
ab -n 1000 -c 6 http://localhost:8080/
(où 1000
désigne le nombre d'invocations au serveur et 6
désigne le
nombre de
connexions simultanées faites au serveur). ab
vous indique les performances de votre serveur ;
- dans un navigateur, tapez
l'adresse http://localhost:8080
: à cause de ces pertes d'incrémentation
potentielle, il est possible que le
navigateur affiche une valeur de compteurReponse
inférieure à la valeur attendue,
c'est-à-dire
1001 (1000
requêtes réalisées par ab
et 1 requête réalisée
par votre navigateur) ;
- arrêtez votre serveur.
Dans
le répertoire Q3-1,
modifiez codeEtudiant.c
pour garantir qu'il n'y
aura aucune perte d'incrémentation de compteurRequete.
---beginCorr
Barème :
- clarté du code : 0,25 ;
- compilation sans warning : 0,25 ;
- test du retour de chaque appel système :
0,25 ;
- réponse correcte à la question
posée :
- déclaration du mutex : 0,5 ;
- encadrement de l'incrémentation par
mutex_lock et mutex_unlock : 0,75.
voir codeEtudiant.Q3-1.corrige.c
---endCorr
Question 3-2 : Sauvegarde de compteurReponse
sur disque (2,5 points)
Jusqu'à
présent, lorsque l'on arrête le serveur, la valeur
courante de
compteurReponse
est perdue. On se propose donc de mémoriser sur disque sa
valeur dans un fichier sauvegardeCompteurReponse
:
- recopiez Q3-1/codeEtudiant.c
dans Q3-2
;
- modifiez Q3-2/codeEtudiant.c
de sorte que :
- au
démarrage du serveur :
- si le fichier sauvegardeCompteurReponse
n'existe pas, il est créé (avec les droits de
lecture-écriture pour vous-même, le groupe et les
autres,
avant modification par le umask)
et compteurReponse
est initialisé à 0 ;
- si le fichier sauvegardeCompteurReponse
existe, compteurReponse
est initialisé à la valeur
mémorisée dans ce fichier ;
- à chaque appel de gestion_compteurReponse,
on sauvegarde la valeur de compteurReponse
dans le fichier.
NB
:
- la valeur de compteurReponse
sera stockée dans le fichier sauvegardeCompteurReponse
sous forme
binaire
ou textuelle, selon votre préférence.
- le fichier sauvegardeCompteurReponse
sera ouvert avec ou sans l'option O_SYNC,
selon votre préférence. En revanche, vous
veillerez
à justifier (dans un commentaire au niveau de l'instruction
d'ouverture du fichier) votre décision par rapport
à
l'utilisation ou la non-utilisation de O_SYNC.
---beginCorr
Barème :
- clarté du code : 0,25 ;
- compilation sans warning : 0,25 ;
- test du retour de chaque appel système :
0,25 ;
- réponse correcte à la question
posée :
- création correcte du fichier : 0,5
(seulement 0,25 si les droits ne sont pas corrects) ;
- traitement correct (lecture bien faite de la valeur
de la variable) si le fichier existe déjà : 0,25 ;
- écriture correcte de la variable : 0,5
(0,25 pour le lseek et 0,25 pour le write proprement dit) ;
- justification par rapport à
l'utilisation de O_SYNC
(vu le flou de l'énoncé, on peut
décider d'utiliser O_SYNC
ou non) : 0,25 ;
- encadrement
de l'incrémentation et éventuellement (ce n'est
pas
obligatoire, car on écrit seulement 1 entier ==>
Ecriture
atomique) de l'écriture dans le fichier par mutex_lock et
mutex_unlock : 0,25.
voir codeEtudiant.Q3-2.corrige.c
pour une sauvegarde dans le fichier au format binaire.
voir codeEtudiant.Q3-2bis.corrige.c
pour une sauvegarde dans le fichier au format texte.
---endCorr
Question 3-3 : Améliorer les performances de
la sauvegarde sur disque (2,5 points)
En
utilisant ab,
on constate que le serveur réalisé à
la question 3-2 voit
ses performances chuter par rapport à celui de la question
3-1. C'est
pourquoi, dans cette question, on met en œuvre
une architecture
logicielle préservant les performances de la question 3-1
tout en
conservant la sauvegarde de compteurReponse
abordée à la question 3-2. Le principe de cette
architecture est de confier l'écriture sur
disque à un thread
spécifique qui
écrit, chaque seconde, la valeur courante de compteurReponse
dans le
fichier sauvegardeCompteurReponse.
Certes, si le serveur tombe, on perd le
décompte de requêtes effectuées depuis
la dernière seconde où ce thread
spécifique s'est activé, mais on
préserve les performances du serveur !
- recopiez Q3-2/codeEtudiant.c
dans Q3-3
;
- modifiez Q3-3/codeEtudiant.c
de sorte que :
- au
démarrage du serveur :
- si le fichier sauvegardeCompteurReponse
n'existe pas, il est créé (avec les droits de
lecture-écriture pour vous-même, le groupe et les
autres)
et compteurReponse
est initialisé à 0 ;
- si le fichier sauvegardeCompteurReponse
existe, compteurReponse
est initialisé à la valeur
mémorisée dans ce fichier ;
- on crée ce thread
spécifique ;
- ce thread
spécifique exécute une boucle sans fin dans
laquelle :
-
il écrit la valeur courante de compteurReponse
dans sauvegardeCompteurReponse
;
- il dort pendant une seconde ;
- à chaque appel de gestion_compteurReponse,
on se contente d'incrémenter compteurReponse
de 1 (sans faire aucune écriture dans le fichier sauvegardeCompteurReponse).
NB
: le fichier sauvegardeCompteurReponse
sera ouvert avec ou sans l'option O_SYNC,
selon votre préférence. En revanche, vous
veillerez à justifier (dans
un commentaire au niveau de l'instruction d'ouverture du fichier) votre
décision par rapport à l'utilisation ou la
non-utilisation de O_SYNC.
---beginCorr
Barème :
- clarté du code : 0,25 ;
- compilation sans warning : 0,25 ;
- test du retour de chaque appel système :
0,25 ;
- réponse correcte à la question
posée :
- création du nouveau thread : 0,25 ;
- code correct pour ce nouveau thread :
- écriture de la valeur : 0,25 ;
- non-encadrement
de l'écriture sur disque par mutex_lock et mutex_unlock :
0,5
(pour avoir l'ensemble de ces 0,5 point, il faut recopier la valeur de
compteurReponse
dans une variable locale (en
protégeant cette recopie via mutex_lock/mutex_unlock),
puis faire l'écriture hors mutex (sinon on bloque tous les
threads incrémenteurs, i.e. on n'a rien gagné par
rapport
à Q3-2) ;
- sommeil : 0,25 ;
- justification par rapport à
l'utilisation de O_SYNC
(on doit l'utiliser, car l'énoncé
suggère qu'on ne
souhaite pas perdre plus de 1 seconde d'incrémentation) : 0,25 ;
- encadrement de
l'incrémentation par mutex_lock et mutex_unlock :
0,25.
voir codeEtudiant.Q3-3.corrige.c
---endCorr
Question 3-4 (question bonus) : Utilisation d'un pool de threads (bonus de 2
points)
Dans
le code actuel, à chaque requête, on
crée un thread
dédié, ce
qui
prend du temps et limite donc les performances globales du serveur.
- recopiez Q3-3/codeEtudiant.c
dans Q3-4
;
- modifiez Q3-4/codeEtudiant.c
de sorte que :
- au
démarrage du serveur, outre les traitements mis en
œuvre à la question
Q3-3, on crée 20
threads
qui se mettent en attente de travail ;
- lors de l'appel à gestion_connexion_entrante,
on confie le traitement de cette connexion à l'un des threads inactifs de
ce pool ;
- lorsqu'un thread
a terminé son appel à handle_connection,
il se remet en attente de travail.
---beginCorr
Barème :
- Clarté du code : 0,25
- Compilation sans warning : 0,25
- Test du retour de chaque appel système :
0,25
- Réponse correcte à la question
posée :
- création des 20 threads (pas
forcément détachées) : 0,25
- implémentation répondant au
problème : 1 point. Pour info, dans le corrigé :
- on crée un tube sur lequel
les 20 threads
se mettent en lecture d'un connexion_fd
;
- gestion_connexion_entrante
écrit la valeur du
paramètre connexion_fd
sur ce tube ;
- un seul des threads
en attente arrive à lire cette valeur. Il appelle handle_connection.
voir codeEtudiant.Q3-4.corrige.c
---endCorr
Question 4 : Priorité aux
rédacteurs
(3 points)
NB
: Cette question est difficile. Nous vous recommandons donc de ne
l'aborder que quand vous aurez terminé les autres questions.
Le
transparent 3.5.2 (Solution de base) du cours
« Synchronisation
entre
processus » présente une
implémentation du
paradigme lecteurs/rédacteurs
qui donne priorité aux lecteurs. Le transparent 3.5.4
(Solution avec
priorités égales) présente une
implémentation de ce paradigme qui met
lecteurs et rédacteurs au même niveau. Ainsi, si
on a la
séquence de demande de lecture/écriture suivante :
- demande de lecture Lecteur1,
- demande de lecture Lecteur2,
- demande d'écriture Rédacteur1,
- demande de lecture Lecteur3,
- demande d'écriture Rédacteur 2,
l'algorithme répond aux demandes de la manière
suivante :
- demande de lecture Lecteur1 accordée,
- demande de lecture Lecteur2 accordée,
- demande d'écriture Rédacteur1
accordée,
- demande de lecture Lecteur3 accordée,
- demande d'écriture Rédacteur2
accordée.
Proposez un algorithme (basé sur des appels aux fonctions P() et V()) pour que
le paradigme donne
systématiquement la priorité aux
écrivains. Ainsi,
dans le cas de la séquence de demande de
lecture/écriture évoquée
précédemment, cet algorithme répondra
aux demandes
de la manière suivante :
- demande de lecture Lecteur1 accordée,
- demande de lecture Lecteur2 accordée,
- demande d'écriture Rédacteur1
accordée,
- demande
d'écriture
Rédacteur2 accordée,
- demande de lecture
Lecteur3 accordée.
Pour cette question, répondez sur votre
copie
ou
bien dans le fichier Q4/reponse4.txt (dans ce
dernier
cas, indiquez sur votre
copie « Réponse dans Q4/reponse4.txt »).
---beginCorr
barème :
- Toutes
les variables sont là : 1 (-
0,125
par
variable manquante, sauf NL_en_attente
qui compte pour 0,25
à moins que
l'algorithme proposé par l'étudiant permette de
s'en abstenir)
- Algorithme des lecteurs correct : 1
- Algorithme des rédacteurs correct : 1
Variables globales ================== Sémaphore mutexG initialisé à 1 Sémaphore mutexL initialisé à 1 Sémaphore mutexR initialisé à 1 Sémaphore mutexAttenteFinR initialisé à 1 int NL = 0 int NL_en_attente = 0 int NR = 0
Algorithme des lecteurs ======================= P(mutexL) NL = NL + 1 si NR >= 1 alors // Il y a des rédacteurs qui souhaitent écrire ou qui écrivent // On doit donc les attendre NL_en_attente = NL_en_attente + 1 V(mutexL) P(mutexAttenteFinR) P(mutexL) si NL_en_attente == NL alors P(mutexG) finsi NL_en_attente = NL_en_attente - 1 sinon si NL == 1 alors P(mutexG) finsi finsi V(mutexL) lectures() P(mutexL) NL = NL - 1 si NL == 0 alors V(mutexG) finsi V(mutexL)
Algorithme des rédacteurs ========================= P(mutexR) NR = NR + 1 V(mutexR) P(mutexG) ecrituresEtLectures() V(mutexG) P(mutexR) NR = NR - 1 si NR == 0 alors P(mutexL) pour i = 1 à NL faire P(mutexAttenteFinR) fpouri V(mutexL) finsi V(mutexR)
---endCorr
|