|
|
Institut National des Télécommunications
Télécom INT 2è année
TP Noté CS21 du 20/06/05
Modalités
Durée : 3 heures
Les trois questions sont indépendantes les unes des autres.
Le barême est donné à titre indicatif des poids
entre les différentes questions. Seront
notés :
- La clarté du code,
- Le fait que le code compile (sans warning),
- Le fait que le code répond correctement à la
question posée,
- Le fait que le retour de chaque appel système, s'il y en
a un, est testé et géré (traitement
d'erreur),
- Le fait que les ressources système
réservées pendant l'exécution du programme
sont libérées à la fin de
l'exécution.
La «livraison» de votre travail en fin de TP
noté se fera par remise de votre copie à l'enseignant
et par
envoi d'un mail à Michel.Simatic@int-evry.fr
(sujet «CS21:TP noté») avec en pièce
jointe le fichier d'extension tgz constitué de
la manière suivante :
cd votreRepertoireDeTravailPourCS21
tar cvfz $USER.tgz TPNote2005
Préparation
cd votreRepertoireDeTravailPourCS21
cp ~simatic/CS21/tPNote2005.tgz .
tar xvfz tPNote2005.tgz
cd TPNote2005
Question 1 : Relecture de code (4,5 points)
Pour chacun des six extraits de code suivants, déterminez s'il
contient des anomalies (erreur de programmation, erreur d'utilisation ou
bien code non optimal).
Pour chaque anomalie trouvée, donnez sa
localisation et une explication sur votre copie ou
bien dans le fichier Q1/reponse.txt (dans ce dernier
cas, indiquez sur votre copie "Réponse dans
Q1/reponse.txt " ).
/*************/
/* Extrait 1 */
/*************/
Ligne 1: int i;
Ligne 2: pid_t pid;
Ligne 3: /* Creation de NBENFANTS enfants */
Ligne 4: for (i=0 ; i<NBENFANTS ; i++){
Ligne 5: pid = fork();
Ligne 6: switch(pid){
Ligne 7: case -1:
Ligne 8: perror("fork");
Ligne 10: exit(EXIT_FAILURE);
Ligne 11: case 0:
Ligne 12: i = NBENFANTS;
Ligne 13: break;
Ligne 14: default:
Ligne 15: break;
Ligne 16: }
Ligne 17: }
/*************/
/* Extrait 2 */
/*************/
Ligne 1: typedef struct {
Ligne 2: short nbTorchons;
Ligne 3: int nbAssiettes;
Ligne 4: short nbServiettes;
Ligne 5: int nbCuillières;
Ligne 6: } materielCuisine;
/*************/
/* Extrait 3 */
/*************/
Ligne 1: int fd;
Ligne 2: int rc;
Ligne 3: int donnee;
Ligne 4: fd = open("unFichier.dat", O_RDONLY|O_SYNC);
Ligne 5: if (fd == NULL){
Ligne 6: perror("fopen");
Ligne 7: exit(EXIT_FAILURE);
Ligne 8: }
Ligne 9: rc = read(fd, &donnee, sizeof(donnee));
Ligne 10: if (rc < 0){
Ligne 11: perror("read");
Ligne 12: exit(EXIT_FAILURE);
Ligne 13: }
/*************/
/* Extrait 4 */
/*************/
Ligne 1: void attenteRequete(void *arg);
Ligne 2: int i;
Ligne 3: for (i=0 ; i<NBTHREADS ; i++) {
Ligne 4: int retcode;
Ligne 5: pthread_t thread;
Ligne 6: retcode = pthread_create(&thread, NULL, attenteRequete, (void *)i);
Ligne 7: if (retcode != 0) {
Ligne 8: perror("pthread_create");
Ligne 9: exit(EXIT_FAILURE);
Ligne 10: }
Ligne 11: pthread_detach(thread);
Ligne 12: }
/*************/
/* Extrait 5 */
/*************/
Ligne 1: void attenteNaissance(void) {
Ligne 2: assert(pthread_mutex_lock(&mutexNaissance) >= 0);
Ligne 3: while (bebeEstNe == FAUX) {
Ligne 4: assert(pthread_mutex_unlock(&mutexNaissance) >= 0);
Ligne 5: assert(pthread_cond_wait(&conditionNaissance, &mutexNaissance) >= 0);
Ligne 6: assert(pthread_mutex_lock(&mutexNaissance) >= 0);
Ligne 7: }
Ligne 8: assert(pthread_mutex_lock(&mutexNaissance) >= 0);
Ligne 10: }
/*************/
/* Extrait 6 */
/*************/
Ligne 1: FILE *f;
Ligne 2: char ligne[TAILLEMAX];
Ligne 3: f = popen("programmeExterne", "r");
Ligne 4: if (f == NULL) {
Ligne 5: perror("popen");
Ligne 6: exit(EXIT_FAILURE;
Ligne 7: }
Ligne 8: while (feof(f) == 0) {
Ligne 9: fflush(f);
Ligne 10: if (fgets(ligne, sizeof(ligne), f) != NULL) {
Ligne 11: traitement(ligne);
Ligne 12: }
Ligne 13: }
Question 2 : En voiture (8 points)
Un constructeur automobile vous demande d'écrire un
simulateur de sa prochaine usine de construction de voitures. Les
composants de cette usine (simplifiée dans la mesure
où on n'en simule que la partie "montage des roues") sont :
- Un "robot transporteur", simulé à l'aide
d'un thread, chargé d'apporter une voiture sur le lieu de
montage, d'attendre le montage de ses roues, puis de la retirer
avant d'appporter un nouveau véhicule, selon l'algorithme
suivant :
robotTransporteur() {
Faire pour toujours
apporterVoitureSurLieuMontage();
signalerVoitureSurLieuMontage();
attendreMontageRoues();
retirerVoitureDeLieuMontage();
Fait;
}
- Quatre "robots monteur de roues", simulés à
l'aide d'un thread par robot, pouvant travailler en
parallèle. Chacun de ces robots prend une roue dans un
distributeur de roues (partagé entre ces quatre robots),
attend qu'un véhicule soit prêt au montage, monte la
roue à l'endroit qui lui est assigné (par exemple,
avant-gauche), selon l'algorithme suivant :
robotMonteurRoues(Localisation localisationSurVoiture) {
Faire pour toujours
Roue roue;
roue = prendreRoueDansDistributeur();
attendreVoitureSurLieuMontage(localisationSurVoiture);
monterRoue(roue, localisationSurVoiture);
signalerMontageDUneRoueTermine();
Fait;
}
- Un "robot chargeur", simulé à l'aide d'un
thread, responsable de mettre des roues dans le distributeur selon
l'algorithme suivant :
robotChargeur() {
Faire pour toujours
mettreRoueDansDistributeur(nouvelleRoue());
Fait;
}
- Un "distributeur", simulé à l'aide d'un tableau
tabRoue de MAXROUES
éléments de type Roue . Le chargement de roues se
fait dans l'ordre des cases tabRoue[0] , tabRoue[1] ...
tabRoue[MAXROUES-1] , tabRoue[0] ... La
prise de roue est également réalisée dans
l'ordre tabRoue[0] , tabRoue[1] ...
tabRoue[MAXROUES-1] , tabRoue[0] ...
Noter que mettreRoueDansDistributeur()
attend si aucune case de tabRoue n'est libre et
prendreRoueDansDistributeur() attend si
aucune case de tabRoue
ne contient de roue.
NB : pour la question 2.1 (respectivement 2.2), vous pouvez
répondre sur votre copie ou bien dans le fichier Q2/reponse21.txt
(respectivement Q2/reponse22.txt ). Dans ce dernier
cas, indiquez sur votre copie "Réponse dans
Q2/reponse21.txt " (respectivement
"Réponse dans Q2/reponse22.txt " )
Question 2.1 : Identification des paradigmes (3
points)
Indiquez les différents types de problème de synchronisation
auquel vous allez être confrontés pour implémenter
ce simulateur (exclusion mutuelle, cohorte,
producteur/consommateur...) en précisant, pour chaque problème,
ses acteurs (par exemple, si vous trouvez qu'il y a un paradigme de
lecteurs/rédacteur dans lequel intervient le "robot chargeur", vous
devez préciser si le "robot chargeur" est lecteur ou
rédacteur).
Question 2.2 : Conception à l'aide de sémaphores (5
points)
À l'aide de sémaphores (munis de leurs
opérations P() et V() ) et de variables que vous
déclarerez de manière globale (i.e. ils seront
accessibles à partir de n'importe quelle
procédure/fonction de votre programme) et initialiserez,
écrivez les algorithmes suivants :
- Procédure
attendreMontageRoues()
- Procédure
attendreVoitureSurLieuMontage(Localisation localisationSurVoiture)
- Procédure
mettreRoueDansDistributeur(Roue
uneRoue)
- Fonction
prendreRoueDansDistributeur() qui
renvoie une entité de type Roue
- Procédure
signalerMontageDUneRoueTermine()
- Procédure
signalerVoitureSurLieuMontage()
Question 3 : Toujours plus de "M. et Mme" (7,5 points)
Pour cette question, vous avez à votre disposition :
- Un serveur de "M. et Mme" constitué d'un processus distributeur
et de 26 processus enfants, chacun de ces derniers étant chargé des "M. et Mme"
commençant par une certaine lettre de l'alphabet :
- Chaque enfant cherche, dans le fichier, la première et la
dernière ligne commençant par sa lettre.
- Sur réception d'une requête, le distributeur fait suivre
la requête à l'enfant correspondant à la 1-ère
lettre du "M. et Mme" :
- L'enfant ne cherche que dans les lignes qui le concernent ;
- Il répond au client ;
- Il attend une requête du processus distributeur.
(Certains reconnaîtront à raison le serveur
développé à la question
6 de l'exercice 1 des exercices Client/Serveur).
- Un client capable d'interroger ce serveur.
L'objectif de cette question est de développer une application
ajout qui permette
d'ajouter dynamiquement des "M. et Mme" au fichier
mEtMme.txt en respectant les
spécifications suivantes :
ajout ne peut
ajouter que quand il est sûr qu'aucun enfant du serveur
n'est en train de
répondre à une requête de "M. et Mme".
ajout doit
insérer le "M. et Mme" fourni en paramètre au bon
endroit dans le fichier (qui est classé
alphabétiquement).
- Quand
ajout
souhaite insérer un "M. et Mme", il n'y a aucun risque qu'il
attende indéfiniment que des enfants du serveur
traitent
des requêtes de "M. et Mme".
Ceci va entraîner des modifications dans le fichier ajout.c ,
mais aussi dans le fichier serveur.c . En effet, les processus
enfants sont impactés dans la mesure où :
- Quand
ajout
insère un nouveau "M. et Mme",
les enfants attendent
qu'ajout ait fini avant de recommencer à traiter
des requêtes de "M. et Mme".
- Après une insertion d'
ajout , avant de
recommencer à traiter des requêtes de "M. et Mme",
les enfants commencent par
réinitialiser la position de la première et de la
dernière ligne commençant par la lettre dont ils sont
responsables.
Travail demandé :
- Indiquez le principe de votre solution sur votre copie ou bien
dans le fichier
principe.txt (dans ce dernier cas, précisez sur
votre copie "Réponse dans Q3/principe.txt ).
-
Modifiez les fichiers
ajout.c et serveur.c
pour obtenir l'ajout dynamique de "M. et Mme".
NB : Pour cette question, il y a 3 problèmes à résoudre
(classés par ordre de difficulté croissante) :
- la synchronisation entre
ajout et les enfants du serveur,
- la mise-à-jour de
mEtMme.txt par ajout ,
- la réinitialisation des enfants
Il est recommandé de les traiter dans cet ordre et de
vérifier qu'un problème est traité avant de passer à la
résolution du problème suivant (pour information, les 3 problèmes
seront notés indépendamment les uns des autres).
|