|
|
TÉLÉCOM SudParis
2ème
année
TP Noté CSC4508/M2 du 22/06/11
(2ème session)
(Corrigés)
Modalités
Durée : 1 heure 30
Tous documents autorisés.
Les questions 1, 2 et 3 sont indépendantes. 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
remontée sous Moodle (rubrique « TP
noté de 1
heure 30 ») du fichier d'extension tgz
constitué de
la manière suivante :
cd votreRepertoireDeTravailPourCSC4508M2 tar cvfz $USER.tgz TPNote2011Session2
Préparation
cd votreRepertoireDeTravailPourCSC4509M2 cp ~simatic/Cours/CSC4508/tPNote2011Session2.tgz . tar xvfz tPNote2011Session2.tgz cd TPNote2011Session2
Question 1 : De l'alignement des structures (6 points)
On considère le programme C suivant :
#include <stdlib.h>
typedef struct {
short aShort;
int anInt;
short aShort2;
}
__attribute__((packed,aligned(8))) MaStruct;
int main() {
MaStruct maStruct = {0,0,0};
maStruct.anInt = 1;
return EXIT_SUCCESS;
}
Pour chacune des questions ci-dessous, répondez dans le fichier Q1/reponse1.txt
ou bien sur votre
copie (dans ce
dernier
cas, indiquez dans le fichier Q1/reponse1.txt
« Réponse sur copie »).
- Expliquez le rôle de l'attribut packed dans __attribute__((packed,aligned(8))).
- Expliquez le rôle de l'attribut aligned(8) dans __attribute__((packed,aligned(8))).
- Sur un processeur Intel, ce programme s'exécute
parfaitement. En revanche, sur un processeur ARM d'ancienne génération, ce programme plante
au niveau de l'instruction maStruct.anInt
= 1; en faisant une « Erreur
d'accès mémoire ». Expliquez pourquoi.
- Quels changements proposez-vous dans ce programme pour que
l'instruction maStruct.anInt = 1; s'exécute correctement sur
processeur ARM ancienne génération ?
---beginCorr
Barème : 1,5 point par réponse apportée
- L'attribut packed permet d'indiquer au compilateur que
cette structure doit être compactée. De ce fait,
même si l'entier n'est pas correctement aligné dans la
structure, le compilateur ne doit pas générer ni 2 octets
de stuffing après aShort, ni 2 autres après aShort2 (ce
que le compilateur ferait automatiquement s'il n'y avait pas cet
attribut packed).
- L'attribut aligned(8) permet d'indiquer au compilateur que
toute variable ayant pour type cette structure doit être
alignée sur une frontière de 8 octets, i.e. son adresse
doit être un multiple de 8 octets.
- A cause de ces 2 attributs, anInt est à cheval sur
une frontière de 4 octets (2 octets avant cette frontière
et 2 octets après). De ce fait, l'accès à anInt
nécessite un traitement spécial que sait faire le
processeur Intel, mais que ne sait pas faire le processeur ARM.
NB :
- S'il n'y avait pas eu l'attribut aligned(8), le
compilateur aurait quand même cherché à aligner la
structure sur une frontière de 4 octets. Donc anInt aurait
été totu de même sur une frontière de 4 octets (cf. Exercice 3
des exercices autour de la Mémoire).
- Les processeurs Intel qui implémentent le jeu
d'instructions MMX sont également confrontés à ce
problème d'accès mémoire sur une frontière
d'octets (cf. Exercice 8 des exercices autour de la Mémoire).
- Il suffit de placer anInt en premier ou en dernier dans
la structure MaStruct. Ainsi, anInt se retrouve sur une frontière de 4
octets : le processeur ARM peut y accéder sans problème.
---endCorr
Question 2 : Le retour de La Trace du Hourra (4 points)
Dans
l'une des questions du TP noté de
2011 (session 1), nous avons étudié l'algorithme de
synchronisation des trains fonctionnant sur la montagne russe La Trace
du Hourra du Parc Astérix.
Rappels (que vous pouvez ne pas lire si vous vous souvenez du TP noté de 2011 [session 1])
La figure 1 modélise cette montagne russe. Elle est
constituée de 4 zones:
- zoneE est la
zone d'Embarquement où les passagers montent et descendent d'un
train. zoneE peut
contenir au maximum 2 trains.
- zoneA est la
zone d'Attente juste avant de pouvoir entrer dans zoneE. Elle ne peut contenir
qu'un train.
- zoneH est la
zone où un train monte avant de se lancer dans sa
descente infernale (c'est donc la zone des Hurlements où les
gens
crient « Help, je veux descendre ! Non, pas comme
çaaaaaaaa... »). Elle ne peut contenir qu'un train.
- zoneG est la
zone de Garage du train. Les trains y sont parqués avant
d'être injectés dans le circuit zoneE-zoneH-zoneA. NB : dans cet
exercice, on suppose qu'une
fois qu'un train est sorti de zoneG,
il n'y retourne plus jamais.
Figure 1 : Modélisation de la montagne russe
« La Trace du
Hourra »
Quand cette attraction fonctionne :
- Un train ne peut quitter zoneG que s'il y a de la place
dans zoneE.
- Un train ne peut quitter zoneE que si zoneH est vide.
- Un train ne peut quitter zoneH que si zoneA est vide.
- Un train ne peut quitter zoneA que s'il y a de la place
dans zoneE.
La question 2 proprement dite
Une
personne, que nous dénommerons Candide par la suite, a
proposé l'algorithme ci-dessous pour chaque train de cette
attraction. Noter que l'algorithme du corrigé du TP noté
de 2011 (session 1) et l'algorithme de Candide ne diffèrent que
par la valeur d'initalisation du sémaphore zoneE.
Semaphore zoneE
initialisé à 1; // Dans le corrigé du TP
noté
// de 2011 (session 1), le
// le sémaphore zoneE était
// initialisé à 2
et non à 1.
Semaphore zoneA
initialisé à 1;
Semaphore zoneH
initialisé à 1;
Procédure codeTrain()
afficher("Je suis dans
zoneG");dormirUnPeu();
P(zoneE);
Tant que VRAI faire
afficher("Je suis dans la zone
zoneE");dormirUnPeu();
P(zoneH)
V(zoneE);
afficher("Je suis dans la zone
zoneH");dormirUnPeu();
P(zoneA);
V(zoneH);
afficher("Je suis dans la zone
zoneA");dormirUnPeu();
P(zoneE);
V(zoneA);
Fin Tant que
Fin Procédure
- Expliquez pourquoi, quand le sémaphore zoneE est
initialisé à 1 (au lieu de 2), la zone zoneE ne peut
contenir qu'un seul train à la fois.
- Quand le sémaphore zoneE est initialisé
à 1 (au lieu de 2), si 3 trains sont injectés dans la
montagne russe, ces trois trains n'arrivent pas à circuler.
Expliquer pourquoi.
---beginCorr
Barème : 2 points par réponse apportée
- Le sémaphore zoneE est initialisé à 1. Donc quand un train rentre dans la zone zoneE, il fait passer ce sémaphore à 0. De ce fait, vu que quand un autre train cherche à rentrer dans la zone zoneE, il commence par faire P(zoneE), il reste bloqué sur ce P(zoneE) tant que l'autre train n'a pas quitté la zone zoneE (et donc fait V(zoneE)). En conséquence, on ne put avoir qu'un seul train dans la zone zoneE.
- Supposons qu'il y ait 3 trains dans le circuit et qu'ils sont tous sortis de la zone zoneG. Comme il ne peut y avoir qu'un train par zone, chacun occupe forcément l'une des 3 zones zoneE, zoneH et zoneA. Or, pour pouvoir quitter sa zone, chaque train T doit franchir le P(semaphoreDeLaZoneSuivante). Comme la zone est occupée par un autre train (qui ne fera V(semaphoreDeSaZone) qu'apres avoir franchi le P(semaphoreDeLaZoneSuivante)), le train T ne peut pas quitter sa zone. Aucun train n'arrive donc à circuler.
---endCorr
Question 3 : Simulation de La Trace du Hourra (10 points)
Candide, la personne évoquée à la question 2, a
développé un programme correspondant à son
algorithme
(cf. question 2). Dans ce programme, Candide crée NB_TRAINS
threads qui exécutent le code de codeTrain() ; le Tant que VRAI faire de l'algorithme est remplacé par un for (nbTours=0 ; nbTours<NB_TOURS ; nbTours++) pour que chaque thread s'arrête après
avoir fait NB_TOURS tours
de montagne russe.
Avant de rentrer dans le vif du sujet, exécutez ce programme :
cd Q3-1 ; make ; ./simulationTraceDuHourra
L'affichage permet d'observer la synchronisation des différents
trains.
Les trois sous-questions suivantes peuvent être traitées
les unes indépendamment des autres.
Question 3-1 : Plusieurs trains dans la zone zoneE (4,5
points)
Comme tous ses sémaphores étaient initialisés
à 1, Candide les a implémentés avec des
pthread_mutex.
Dans cette question, on souhaite pouvoir avoir deux trains en
même temps dans la zone zoneE et donc, comme on l'a vu à la question Q2, 3 trains qui circulent en
parallèle sur la montagne russe.
Dans simulationTraceDuHourra.c, mettez la valeur de NB_TRAINS à
3 et remplacez le pthread_mutex zoneE par un sémaphore de type sem_t
initialisé à (NB_TRAINS - 1).
---beginCorr
Barème :
- Il
y a 1 sem_init, 1 sem_destroy, 2 sem_post et 2 sem_wait : si chaque
appel est bien fait, on compte 0,5 points par appel (soit un total de 3
points).
- Dans le error_at_line qui suit chacune de ces instructions,
on doit mettre errno en 2ème paramètre à la place
de rc. On compte 0,25 point par errno à la place de rc (soit un
total de 1,5 points)
- Pénalité si code compile avec des warnings : -0,5 point
Voir fichier simulationTraceDuHourra.Q3-1.corrige.c
---endCorr
Question 3-2 : Synchronisation du main avec les threads (3 points)
Dans le code actuel, le main
dort après avoir créé les threads.
Ainsi, Candide est sûr que tous les threads sont terminés
quand le main se
réveille et termine son exécution.
Dans simulationTraceDuHourra.c, remplacez sleep(20) par une attente
explicite de la fin de l'exécution des différents threads.
---beginCorr
Barème :
- Dans les pthreads_create, il faut remplacer les &thread par &thread[i] : 1 point
- Boucle avec pthread_join : 1 point
- 2ème paramètre correct dans le pthread_join : 0,5 point
- Test d'erreur après pthread_join : 0,5 point
- Pénalité si code compile avec des warnings : -0,5 point
Voir fichier simulationTraceDuHourra.Q3-2.corrige.c
Dans les pthreads_create, il faut remplacer les &thread par
&thread[i].
Après la boucle de démarrage des threads, il faut faire une boucle avec pthread_join()
---endCorr
Question 3-3 : Où les threads deviennent des enfants (2,5 points)
Dans le code actuel, utilisez des enfants à la place des threads.
---beginCorr
Barème :
- fork() correctement codé : 0,5 points
- Passage du paramètre numTrain à la procédure déroulant le code du train correct : 0,5 points
- wait() correctement codé : 0,5 points
- Création et initialisation des 3 sémaphores : 0,3 points (0,1 point par sémaphore)
- Destruction des 3 sémaphores : 0,3 points (0,1 point par sémaphore)
- Appel à P() et V() : 0,4 points (0,05 point pour chacun des 8 appels)
- Pénalité si code compile avec des warnings : -0,5 point
Voir fichier simulationTraceDuHourra.Q3-3.corrige.c
---endCorr
|