Département INFormatique 
  CSC4508/M2 : Concepts des systèmes d'exploitation et mise en œuvre sous Unix


    Contenu



Entrées-sorties

(Corrigés)

Exercice 1 : Nombre d'octets à écrire et performances

Préparation

Se placer dans un répertoire de travail
tar xvfz perfW.tgz
cd PerfW

Question 1

Compléter toutes les sections "/* A vous de compléter */" du fichier pw.c
make
---beginCorr
pw.corrige.c
---endCorr

Question 2

Ca y est : "pw.c compile" !
/usr/bin/time pw 16
Puis 32, 64 et toutes les puissances de 2 jusqu'à 8192. Pour automatiser ce traitement, on peut s'appuyer sur les capacités de bash:
  • for i in 16 32 64 128 256 512 1024 2048 4096 8192; do echo $i; /usr/bin/time pw $i; done
  • ou bien
    for ((i=16; i<= 8192; i*=2)); do echo $i; /usr/bin/time pw $i; done
Qu'en concluez-vous ?
---beginCorr
Plus les blocs utilisés pour l'écriture sont gros, plus ça va vite et surtout moins on utilise la CPU. A partir d'une certaine taille de bloc, on atteint une asymptote.
---endCorr

Question 3

Rajouter l'option O_SYNC à votre fonction open()
/usr/bin/time pw 512
/usr/bin/time pw 8192
Qu'en pensez-vous ?
---beginCorr
Les performances chutent de manière dramatique. En revanche, avec O_SYNC, on a la garantie que, lorsqu'on revient du write, les octets sont physiquement présents sur le disque.
---endCorr

Question 4

Recopier pw.c en pwWritev.c
Modifier pwWritev.c en :
  • Retirant l'option O_SYNC de la fonction open(),
  • Ecrivant le fichier à l'aide de la fonction writev (au lieu de write). writev devra être appelé avec, en paramètre, 8192/param_appel_a_pwWritev structures iovec pointant sur des zones de param_appel_a_pwWritev octets.
Compiler pwWritev
Comparer les performances de pw 16, pw 8192, pwWritev 16, et pwWritev 8192
---beginCorr
pwWritev.corrige.c
Voici les performances obtenues sur une machine équipée d'un processeur Intel Core 2 Duo CPU E4500  @ 2.20GHz, munie de 2 Go de RAM
$ /usr/bin/time pw 16
0.65user 13.95system 0:14.62elapsed 99%CPU (0avgtext+0avgdata 1424maxresident)k
0inputs+278528outputs (0major+122minor)pagefaults 0swaps
$ /usr/bin/time pw 8192
0.00user 0.23system 0:00.71elapsed 32%CPU (0avgtext+0avgdata 1456maxresident)k
0inputs+332704outputs (0major+139minor)pagefaults 0swaps
$ /usr/bin/time pwWritev 16
0.00user 0.48system 0:00.78elapsed 61%CPU (0avgtext+0avgdata 1472maxresident)k
0inputs+524824outputs (0major+125minor)pagefaults 0swaps
$ /usr/bin/time pwWritev 8192
0.00user 0.27system 0:00.60elapsed 44%CPU (0avgtext+0avgdata 1440maxresident)k
0inputs+762312outputs (0major+123minor)pagefaults 0swaps

pwWritev 16 écrit avec des blocs de 16 octets. Mais comme ces blocs sont écrits par "gros" paquets représentant 8192 octets. pwWritev 16 a des performances similaires à celle de pw 8192 , soit un gain de 95% en temps d'exécution par rapport à pw 16. pwWritev 8192 est plus performant (en temps d'exécution) que pw 8192. Mais cela est peut-être dû à une imprécision dans les mesures qui auraient dues être faites plusieurs fois.
---endCorr

Exercice 2 : Comment écrire par blocs de 8192 octets alors que l'application écrit par blocs de 16 octets et ce qu'on y gagne

Préparation

Se placer dans un répertoire de travail
tar xvfz cmpW.tgz
cd CmpW

Question 1

Dans cw.c, comparer ecritMethode1() et ecritMethode2().
Pourquoi à la fin de ecritMethode2() doit-on appeler flushBuf() ?
---beginCorr
Ces 2 fonctions écrivent un fichier au même contenu, mais de manière différente :
  • ecritMethode1() écrit le fichier /var/tmp/ficTest1 en écrivant 16 octets par 16 octets, physiquement dans le fichier.
  • ecritMethode2() écrit le fichier /var/tmp/ficTest2 en écrivant 16 octets, par 16 octets et en passant par un buffer de manière à n'écrire physiquement dans le fichier que tous les 8192 octets. FlushBuf() garantit qu'il n'y pas d'octets qui reste dans ce buffer quand on a fini d'écrire et qu'on se prépare à fermer le fichier.
---endCorr

Question 2

On souhaite comparer ces 2 méthodes d'écriture. Pour ce faire, on va "instrumenter" (faire un "profiling", si on utilise la terminologie anglaise) le programme cw.
Taper
    make cw
Que fait cette instruction ?
Noter que :
  • L'option -pg qui demande l'instrumentation
Taper
    make run
Que fait cette instruction ?
Noter que:
  • "/usr/bin/time cw" exécute le programme et génère un fichier contenant les résultats du "profiling" : gmon.out
  • "gprof cw > resultat.txt" génère une version compréhensible par un humain du fichier gmon.out, génération qu'on redirige vers le fichier resultat.txt
Voici un exemple commenté du fichier resultat.txt (les commentaires sont signalés par des "//"). Consulter le pour voir le type d'informations qu'on peut exploiter avec ce profiling.
Analyser (rapidement) votre propre fichier resultat.txt.
---beginCorr
make cw compile le programme en l'instrumentant.
"make run" exécute cw et génère resultat.txt
---endCorr

Question 3

Mêmes manipulations qu'à la question 2 en ajoutant O_SYNC au moment du open des fichiers *et* en diminuant d'au moins un facteur 50 la taille des fichiers tests générés.
---beginCorr
À compléter
---endCorr

Exercice 3 : Calcul du nombre de lignes

  • Écrire un programme qui lit un fichier et affiche le nombre de lignes de ce fichier.
  • Compléter ce programme pour que le nom du fichier soit passé en argument.
  • Ajouter un test sur la nature de cet argument : s'il s'agit d'un fichier, compter et afficher son nombre de lignes, sinon, afficher seulement son type : répertoire ou fichier spécial.
  • Compléter ce programme de la façon suivante : quand l'argument est un répertoire, il faut alors se déplacer sous ce répertoire, et afficher le nombre de lignes de tous les fichiers ordinaires qu'il contient et seulement le nom pour les autres entrées.
Remarque : il faut penser à tester l'exécution des fonctions (par exemple si le répertoire est inaccessible, la fonction chdir échoue).
---beginCorr
nb_lignes.corrige.c
---endCorr

Exercice 4 : Informations SGF

  • Écrire un programme qui sera exécuté avec en argument un nom de fichier ou de répertoire. Ce programme affichera alors le nombre de blocs total, le nombre de blocs libres, le nombre d'inodes total et le nombre d'inodes libres du système de fichiers auquel appartient cet argument.
Les résultats de ce programme pourront être vérifiés avec les résultats de la commande df. (attention : selon les versions, df utilise des blocs de 512 ou de 1K octets).
---beginCorr
info_sgf.corrige.c
---endCorr

Exercice 5 : Méthode pour trouver "instantanément" la i-è ligne d'un fichier texte

On se propose de développer un programme gl.c (pour GotoLigne) permettant de trouver "instantanément" la ième ligne d'un fichier texte dont les lignes ont des longueurs différentes (inférieures à 1024 caractères, caractère de nouvelle ligne inclus).
Le principe de la solution retenue est le suivant pour trouver la iè ligne du fichier mEtMme.txt :
  • Avant l'utilisation de gl.c, on construit (à l'aide du programme d'initialisation gli) un fichier mEtMme.txt.idx tel que :
    • Les 4 premiers octets du fichier mEtMme.txt.idx contiennent le décalage écrit en binaire de la 1ère ligne de mEtMme.txt (par rapport au début de mEtMme.txt), i.e. 0x00000000 (zéro).
    • Les 4 suivants contiennent le décalage de la 2ème ligne de mEtMme.txt, i.e. longueur de la 1ère ligne. Par exemple, 0x07000000 (et non 0x00000007, car le processeur Intel est Little Endian ; NB: vous n'aurez rien de spécial à faire dans votre programme pour prendre en compte le Little Endian) si la 1ère ligne de mEtMme.txt contient "Coucou\n".
    • Les 4 suivants contiennent le décalage de la 3ème ligne de mEtMme.txt, i.e. longueur de la 1ère ligne + longueur de la 2ème. Par exemple, 0x0d000000, si la 2ème ligne contient "Hello\n".
  • Au moment de l'exécution de gl.c :
    • On ouvre le fichier mEtMme.txt.idx
    • Grâce à lseek on se décale pour se placer au niveau des octets correspondant au décalage du numéro de ligne cherchée
    • On lit, dans un entier, les 4 octets correspondant au numéro de ligne cherchée
    • On lit également les 4 octets correspondant au numéro de ligne recherché + 1 (on connaît ainsi la longueur de la ligne cherchée)
    • On ouvre le fichier mEtMme.txt
    • On se décale de la valeur des 4 octets correspondant à la ligne cherchée
    • On lit le fichier pour récupérer toute la ligne

Question 1

Écrire le programme d'initialisation "gli" (à l'aide des fonctions de la bibliothèque C d'entrées-sorties). Ce programme lit sur la ligne de commande le nom du fichier pour lequel il faut générer le fichier d'index (le nom du fichier d'index est le nom du fichier original concaténé avec ".idx").
---beginCorr
gli.corrige.c
---endCorr

Question 2

Écrire le programme "gl" (à l'aide des fonctions de la bibliothèque C d'entrées-sorties). Ce programme lit sur la ligne de commande le nom du fichier et le numéro de ligne. Il affiche la ligne.
---beginCorr
gl.corrige.c
---endCorr

Question 3

Écrire une nouvelle version de "gl" (glMmap) qui utilise mmap pour permettre la lecture des octets du fichier d'index sans utiliser fread ou read.
---beginCorr
glMmap.corrige.c
---endCorr

Exercice 6 : Accès concurrents et NFS

Question 1

Écrire un programme "nfs" qui :
  • Lit sur la ligne de commande :
    • le nom du fichier à ouvrir
    • une chaîne de caractère(s).
  • Ouvre le fichier en mode écriture seulement, création  si n'existe pas et mode "ajout" (droits lecture/écriture pour l'utilisateur seulement).
  • Écrit 10.000.000 de fois la chaîne de caractères dans le fichier.
---beginCorr
nfs.c
---endCorr

Question 2

Lancer la commande "nfs /var/tmp/ficTest a" sur 2 terminaux différents en parallèle. Faire "ls -l /var/tmp/ficTest". Que pensez-vous de la taille du fichier obtenu ? Effacer le fichier /var/tmp/ficTest
---beginCorr
Le fichier obtenu fait 20.000.000 de caractères, ce qui est normal vu que l'un des programmes a écrit 10.000.000 de caractères et que l'autre aussi.
---endCorr

Question 3

Même opération avec le fichier ~/ficTest avec:
  1. les 2 terminaux étant sur la même machine (ne pas oublier d'effacer le fichier obtenu) : pourquoi a-t-on le même comportement qu'à la question 1 ?
  2. les 2 terminaux sur une machien différente : pourquoi perd-on des écritures ?
---beginCorr
Dans le premier cas, le fichier obtenu fait 20.000.000 de caractères, ce qui est normal vu que l'un des programmes a écrit 10.000.000 de caractères, que l'autre aussi et que les deux programmes passent par le même serveur NFS (vus qu'ils sont sur la même machine).
En revanche, dans le second cas, des écritures sont perdus ! Par exemple, l'auteur de l'exercice a obtenu une taille finale de 11.075.971 octets. En effet, NFS ne forwarde pas immédiatement ses écritures au serveur ==> Les écritures de l'un des programmes peuvent écraser les écritures d'un autre programme.
---endCorr

Exercice 7 : Gestion d'une banque

Préparation

Se placer dans un répertoire de travail
tar xvfz banque.tgz
cd Banque
---beginCorr
0,25 points sont attribués si l'indentation des différents sources est correcte.
0,25 points sont attribués si les trois codes compilent sans warning (ni erreur).
0,5 points seront attribués si les types sont corrects (double) et les pointeurs aussi.
---endCorr

Recommandation

Dans cette exercice, vous allez écrire du code. Et ce code, vous allez le tester pour le vérifier. Il est recommandé d'effecturer ces tests avec un numéro de compte autre que le compte numéro 0 (zéro) pour éviter de passer à côté de certaines erreurs (impossibles à voir avec le compte numéro 0).

Question 0

On souhaite écrire un programme pour la gestion d'une banque. Ce programme manipule un fichier de données ("banque.dat") contenant NBCOMPTES comptes en banque. Chaque compte est identifié par un numéro correspondant au rang du compte dans le fichier (par exemple, le compte numéro 0 apparaît en premier dans le fichier) et est représenté dans le fichier par un nombre décimal (éventuellement négatif) correspondant au solde du compte.

Dans cette question, on suppose que NBCOMPTES vaut 4 et que les 4 comptes ont respectivement pour solde : -10,02 euros, 1235,43 euros, 150000,43 euros et 9999999,99 euros.

On considère les trois implémentations suivantes du fichier :
  • Implémentation 1 :
    -10.02[caractère(s) de renvoi à la ligne]
    1235.43[caractère(s) de renvoi à la ligne]
    150000.43[caractère(s) de renvoi à la ligne]
    9999999.99[caractère(s) de renvoi à la ligne]
     
  • Implémentation 2 :
        -10.02[caractère(s) de renvoi à la ligne]
       1235.43[caractère(s) de renvoi à la ligne]
     150000.43[caractère(s) de renvoi à la ligne]
    9999999.99[caractère(s) de renvoi à la ligne]
     
  • Implémentation 3 :
    XXXXXXXXYYYYYYYYZZZZZZZZTTTTTTTT
    où X (respectivement Y, Z et T) représente 1 octet, XXXXXXXX (respectivement YYYYYYYY, ZZZZZZZZ et TTTTTTTT) correspondant à la valeur binaire du double contenant le solde du compte numéro 0 (respectivement 1, 2 et 3). 
Dans le fichier reponses.txt, calculez (en justifiant brièvement) pour chacune de ces implémentations :
  • Le nombre d'octets requis pour stocker les 4 comptes (pour les implémentations 1 et 2, on distinguera le cas Unix et le cas Windows)
  • Le nombre d'octets qui doivent être lus sur disque pour disposer en mémoire du solde du compte numéro 3 (traiter uniquement le cas Unix).
---beginCorr
Barême : 1 point pour les calculs (et justification) liés à chaque implémentation, soit un total de 3 points.
  • Implémentation 1 :
    • Sous Unix, on a besoin de : 7 + 8 + 10 + 11 = 36 octets. Sous Windows, 4 octets de plus sont nécessaires, car le renvoi à la ligne est codé sur 2 octets (CarriageReturn suivi de LineFeed).
    • Dans cette implémentation, comme les différentes lignes n'ont pas la même dimension, on est obligé de lire les lignes qui précèdent celle qu'on souhaite lire. On aura donc besoin de lire 36 octets. NB : on a besoin de lire le caractère de renvoi à la ligne final pour savoir que la lecture de la ligne (et donc du flottant) est terminée.
  • Implémentation 2 :
    • Sous Unix, on a besoin de : 11 + 11 + 11 + 11 = 44 octets. Sous Windows, 4 octets de plus sont nécessaires, car le renvoi à la ligne est codé sur 2 octets (CarriageReturn suivi de LineFeed).
    • Dans cette implémentation, comme les différentes lignes ont la même dimension, pour accéder au compte numéro 3, on peut faire un seek (ou un fseek, selon la librairie qu'on utilise) pour se positionner sur le 3x11=33è octet du fichier et ainsi lire directement la ligne correspondant au compte numéro 3, soit 10 octets (on peut se passer de lire le caractère de renvoi à la ligne puisqu'on sait qu'il est forcément en 11ème position).
  • Implémentation 3 :
    • On a besoin de : 8 + 8 + 8 + 8 = 32 octets.
    • Dans cette implémentation, comme les différentes comptes ont la même dimension (ce sont des double stockés en binaire), pour accéder au compte numéro 3, on peut faire un seek (ou un fseek, selon la librairie qu'on utilise) pour se positionner sur le 3x8=24è octet du fichier et ainsi lire directement la ligne correspondant au compte numéro 3. Il reste à lire les 8 octets correspondant au double.
---endCorr
Dans les questions suivantes, on décide de privilégier l'implémentation 3 qui minimise le nombre d'octets et le nombre de lectures de fichier requises. Vous pouvez réaliser cette implémentation soit avec les fonctions système d'accès aux fichiers (read, write...), soit avec les fonctions de la librairie C (fread, fwrite..). Mais dans le cas des fonctions de la librairie C, veillez à inhiber le tampon d'écriture des fichiers (avec setvbuf) sous peine d'avoir des anomalies de fonctionnement.

Question 1

Compléter le fichier banque.c de manière à ce qu'il implémente l'algorithme suivant :

Lecture des paramètres d'appel du programme
Ouverture fichier "banque.dat"
Lecture du solde stocké dans le fichier
Affichage de ce solde
sleep(5)
si (typeOp == 'L') alors
   Lecture du solde stocké dans le fichier
   Affichage du solde
sinon
   Calcul du nouveau solde
   Ecriture de ce nouveau solde dans le fichier
finsi
Fermeture du fichier


NB : si le fichier "banque.dat" n'existe pas, il faut le créer en l'initialisant avec NBCOMPTES valeurs de type double, chacune étant initialisées à 0 et correspondant au solde de chacun des comptes gérés par la banque.

Vérifier le fonctionnement correct de l'application.
---beginCorr
Barême :
  • 1 point pour l'ouverture "banque.dat"
  • 1 point pour la création de "banque.dat" s'il n'existe pas.
  • 1 point (0,5 pour le lseek et 0,5 pour le read) pour la lecture du solde.
  • 1 point (0,5 pour le lseek et 0,5 pour le write) pour l'écriture du solde.
banque.corrige.c
---endCorr

Question 2

Ouvrir une deuxième fenêtre et placez-vous également dans le répertoire Banque de votre répertoire de travail
Taper "banque 0 L" ("L" comme "Lecture") dans la première fenêtre (sans taper return)
Taper "banque 0 M -5" ("M" comme "Modification" ou "Mise-à-jour" dans la deuxième fenêtre et appuyer sur return
Revenir dans la première fenêtre et appuyer sur return
Pourquoi "banque 0 L" affiche 2 soldes différents au cours de son exécution ? Ce comportement est-il acceptable par un client ? Pour ces 2 questions, vous veillerez à répondre dans le fichier reponses.txt.
---beginCorr
"banque 0 M -5" affiche "Solde initial du compte 0 =       0.00"
"banque 0 L" affiche "Solde initial du compte 0 =       0.00", puis (après 5 secondes) "Solde du compte 0 =       5.00". En effet, pendant son sleep(5), "banque 0 M -5" finit son exécution et donc modifie le solde du compte. La deuxième lecture de "banque 0 L" est donc différente.
Le client devrait accepter ce léger dysfonctionnement (il ne lui porte pas préjudice), même si ça peut le troubler.
Barême :
  • 1 point pour l'explication ?
  • 0,5 pour l'explication de l'acceptabilité.
---endCorr

Question 3

Taper "banque 0 M -10" dans la première fenêtre (sans taper return)
Taper "banque 0 M -5" dans la deuxième fenêtre et appuyer sur return
Revenir dans la première fenêtre et appuyer sur return
Attendre la fin de l'exécution de ces 2 programmes, puis exécuter "banque 0 L".
Commenter le résultat. Ce comportement est-il acceptable par un client ? Vous veillerez à répondre dans le fichier reponses.txt.
---beginCorr
Le premier "banque 0 M -5" affiche "Solde initial du compte 0 =       5.00". Le second aussi. "banque 0 L" affiche "Solde initial du compte 0 =       15.00", puis (après 5 secondes) "Solde du compte 0 =       15.00".
L'écriture de "banque 0 M -5" a été écrasée par l'écriture de "banque 0 M -10" ! On a donc perdu une écriture, ce que le client n'acceptera pas (surtout quand il s'agit d'un crédit sur son compte ;-) ).
Barême :
  • 1 point pour le commentaire
  • 0,5 point pour l'explication de l'acceptabilité
---endCorr

Question 4

On souhaite corriger les dysfonctionnements observés aux questions 2 et 3. Pour ce faire, on souhaite tester une solution consistant en la pose du verrou le plus adapté aux circonstances. L'algorithme envisagé est le suivant :

Lecture des paramètres d'appel du programme
Ouverture fichier "banque.dat"
Pose verrou en lecture // Nouveau par rapport a la question 1
Lecture du solde stocké dans le fichier
Affichage de ce solde
sleep(5)
si (typeOp == 'L') alors
   Lecture du solde stocké dans le fichier
   Affichage du solde
sinon
   Pose verrou en écriture
// Nouveau par rapport a la question 1
   Calcul du nouveau solde
   Ecriture de ce nouveau solde dans le fichier
finsi
Relâchement verrou
// Nouveau par rapport a la question 1
Fermeture du fichier

Faire la commande cp banque.c banqueQ4.c
Implémenter l'algorithme ci-dessus dans la banqueQ4.c
Vérifier que les manipulations de la question 2 n'entraînent plus de dysfonctionnement.
Constater qu'en revanche, les manipulations de la question 3 donnent lieu à une erreur. Expliquer, dans le fichier reponses.txt, le message d'erreur.
---beginCorr
Barême
  • 1 point pour la pose de verrou en lecture
  • 1 point pour la pose de verrou en écriture
  • 1 point pour le relâchement de verrou
  • 2 points pour l'explication du message d'erreur
banqueQ4.corrige.c contient le corrigé.
Lors des manipulations de la question 3, on a les messages suivants
     L'un des processus fait                                                                                                                                                                                 
        tentative de pose de verrou (partage) par processus 11214...                                                                                                                                         
        ...Verrou (partage) pose par 11214                                                                                                                                                                   
        Solde initial du compte 0 =    -200.00                                                                                                                                                               
        tentative de pose de verrou (exclusif) par processus 11214...                                                                                                                                        
        ... Verrou (exclusif) pose par processus 11214                                                                                                                                                       
        Relachement verrou par processus 11214...                                                                                                                                                            
        ...OK                                                                                                                                                                                                
     tandis que l'autre fait:                                                                                                                                                                                
        tentative de pose de verrou (partage) par processus 11215...                                                                                                                                         
        ...Verrou (partage) pose par 11215                                                                                                                                                                   
        Solde initial du compte 0 =    -200.00                                                                                                                                                               
        tentative de pose de verrou (exclusif) par processus 11215...                                                                                                                                        
        Pose verrou: Resource deadlock avoided          
Quand le premier processus essaye de poser son verrou en écriture, Unix constate qu'il faut que ce processus attende que le deuxième processus ait relâché le verrou qu'il détient pour l'instant en lecture. Donc, il met le premier processus en attente. Quand le deuxième processus essaye de poser son verrou en écriture, Unix constate que ce processus doit attendre que le premier processus ait relâché le verrou qu'il a en lecture. Or, ce premier processus ne peut pas relâcher ce verrou puisqu'il est déjà en attente d'un relâchement de la part du deuxième processus. Par conséquent, si jamais Unix met en attente le deuxième processus, il y aura "verrou mortel" (les deux processus s'attendront mutuellement jusqu'à la fin des temps). Pour empêcher ça, Unix signale un message d'erreur pour cette demande de pose de verrou.
Le deuxième processus arrête donc son exécution. De ce fait, il relâche automatiquement son verrou en lecture. Le premier processus peut donc acquérir son verrou en écriture et continuer son exécution.
---endCorr

Question 5

On souhaite corriger le dysfonctionnement observé à la question 4. Une personne propose l'algorithme suivant :

Lecture des paramètres d'appel du programme
Ouverture fichier "banque.dat"
Pose verrou en lecture
Lecture du solde stocké dans le fichier
Affichage de ce solde
sleep(5)
si (typeOp == 'L') alors
   Lecture du solde stocké dans le fichier
   Affichage du solde
sinon
  
Relâchement verrou // Nouveau par rapport a la question 4
   Pose verrou en écriture
   Calcul du nouveau solde
   Ecriture de ce nouveau solde dans le fichier
finsi
Relâchement verrou

Fermeture du fichier

Indiquez dans le fichier reponses.txt ce que vous pensez de cette proposition. NB : il n'est pas demandé d'écrire un programme banqueQ5.c, même si ça peut aider.
---beginCorr
Barême : 2 points pour le commentaire
Le dysfonctionnement de la question 4 est effectivement corrigé. Mais on retrouve le dysfonctionnement de la question 3 ! En effet, quand le deuxième processus relâche son verrou avant de chercher à poser son verrou en écriture, il décoince le premier processus. Ce dernier est donc en mesure d'écrire son nouveau solde. Donc, quand le deuxième processus acquiert le verrou en écriture, il calcule le solde en partant de l'ancienne valeur du solde. Le solde écrit par le premier processus est perdu !
---endCorr

Question 6

Pour corriger tous les dysfonctionnements, une personne propose l'algorithme suivant (consistant à poser dès le début le verrou le plus fort dont on aura besoin) :

Lecture des paramètres d'appel du programme
Ouverture fichier "banque.dat"
si (typeOp == 'L') alors // Nouveau par rapport a la question 4
   Pose verrou en lecture // Nouveau par rapport a la question 4
sinon                     // Nouveau par rapport a la question 4
   Pose verrou en écriture// Nouveau par rapport a la question 4
finsi                     // Nouveau par rapport a la question 4
Lecture du solde stocké dans le fichier
Affichage de ce solde
sleep(5)
si (typeOp == 'L') alors
   Lecture du solde stocké dans le fichier
   Affichage du solde
sinon
   // Nouveau par rapport a la question 4 (plus de "Pose verrou en écriture")
   Calcul du nouveau solde
   Ecriture de ce nouveau solde dans le fichier
finsi
Relâchement verrou

Fermeture du fichier

Faire la commande cp banque.c banqueQ6.c
Implémenter l'algorithme ci-dessus dans la banqueQ6.c
Vérifier qu'il n'y a plus de dysfonctionnement.

---beginCorr
Barême : 2 points pour l'implémentation correcte de l'ensemble
banqueQ6.corrige.c contient le corrigé.
---endCorr

Question 7

banqueQ7 a en fait encore un dysfonctionnement !
Ouvrir une troisième fenêtre :
  • Taper "banque 0 M -10" dans la première fenêtre (sans taper return)
  • Taper "banque 0 L" dans la deuxième fenêtre (sans taper return)
  • Taper "banque 0 L" dans la troisième fenêtre et appuyez sur return
  • Aller dans la première fenêtre et appuyer sur return
  • Aller dans la deuxième fenêtre et appuyer sur return
  • Dès que "banque 0 L" a fini dans la troisième fenêtre, relancer le.
  • Dès que "banque 0 L" a fini dans la deuxième fenêtre, relancer le.
  • On observe que "banque 0 M -10" n'arrive jamais à s'exécuter !
Ce dysfonctionnement ne pourra être corrigé que lors de l'exercice CommInterProcessus/7
---beginCorr
Le phénomène observé est une famine de rédacteur face à de nombreux lecteurs (cf. chapitre "Synchronisation des processus").
---endCorr



Page mise à jour le 28 mars 2012