*Ecole Nationale des Sciences de l’Informatique A. U. : 2014/2015*
*Systèmes d’exploitation & Programmation Concurrente II2*
**TP 2 - Synchronisation de Threads**
**=======================================================**
**Exercice 1:**
Un enseignant d’info a prévu faire un rattrapage pour ses groupes dans une salle de TP. L’unique salle de TP disponible peut contenir uniquement 10 étudiants. Cependant le nombre total des étudiants de ces groupes est égal à 80. Pour cette raison, l’enseignant s’est trouvé obligé de donner cette séance de rattrapage plusieurs fois. Pour ce faire, il a utilisé l’algorithme suivant : L’enseignant ouvre la porte, attend jusqu’à ce que la salle devienne pleine, ferme la porte, donne la séance de rattrapage et ouvre la porte pour laisser sortir les étudiants. Par la suite, il répète ce même processus maintes fois jusqu’à ce que tous les étudiants aient assisté à la séance de rattrapage. Evidemment, entre temps, certains étudiants doivent attendre leur tour pour accéder à la salle de TP.
Nous allons modéliser ce scénario avec un programme multithreadé. On suppose qu’il existe un thread enseignant et 80 threads étudiants. Ci-dessous, vous trouvez le thread enseignant est implémenté en entier, et une partie du thread étudiant. Votre tâche consiste à terminer l’implémentation du thread étudiant.
**Note** : Pour terminer l’implémentation de ce thread, vous ne devez pas déclarer d’autres variables. Par contre, vous pouvez ne pas utiliser toutes les variables déclarées dans le code ci-dessous. Nous supposons que les fonctions ouvrir\_porte(), fermer\_porte(), et enseigner() sont définies et implémentées quelque part ailleurs.
/\* Code \*/
#define ETUDIANTS 80
#define CLASS 10
/\* Déclarations à ne pas modifier \*/
Int etudiants\_entrant = 0; /\* etudiants entrant la salle\*/
int etudiants\_sortant = 0; /\* etudiants quittant la salle room \*/
sem\_t mutex1;
sem\_t mutex2;
sem\_t mutex3;
sem\_t entrer\_file;
sem\_t sortir\_file;
sem\_t tous\_entres;
sem\_t tous\_sortis;
/\* Ne rien modifier ici \*/
int main()
{
Publicité
pthread\_t tid, student\_tid[ETUDIANTS];
int i;
/\* initialize our semaphores \*/
sem\_init(&mutex1, 0, 0);
sem\_init(&mutex2, 0, 1);
sem\_init(&mutex3, 0, 1);
sem\_init(&entrer\_file, 0, 0);
sem\_init(&sortir\_file, 0, 0);
sem\_init(&tous\_entres, 0, 0);
sem\_init(&tous\_sortis, 0, 0);
pthread\_create(&tid, NULL, thread\_enseignant, NULL);
for (i = 0; i < ETUDIANTS; i++) {
pthread\_create(&student\_tid[i], NULL, thread\_etudiant, (void \*)i);
}
for (i = 0; i < ETUDIANTS; i++) {
pthread\_join(student\_tid[i], NULL);
}
printf("C’est tout.\n");
exit(0);
}
/\* thread\_enseignant – ne rien modifier ici \*/
void \*thread\_enseignant(void \*arg)
{
int i;
Publicité
ouvrir\_porte();
while (1) {
for (i = 0; i < CLASS; i++) {
V(&entrer\_file);
}
P(&tous\_entres);
Fermer\_porte();
enseigner();
ouvrir\_porte();
for (i = 0; i < CLASS; i++) {
V(&sortir\_file);
}
P(&tous\_sortis);
}
}
**Question:**
Complétez le code pour la fonction thread\_etudiant() qui suit. Vous ne devez pas ajouter d’autres variables mais vous pouvez ne pas utiliser certaines variables déclarées.
**Note:** Vous devez uniquement ajouter quelques lignes de code ici sans pour autant changer la structure de base de cette fonction.
void \*thread\_etudiant(void \*arg)
{
/\* entrer dans la salle \*/
etudiants\_entrant += 1;
if (etudiants\_entrant == CLASS) {
etudiants\_entrant = 0;
Publicité
}
/\* Quitter la salle \*/
etudiants\_sortant += 1;
if (etudiants\_sortant == CLASS) {
etudiants\_sortant = 0;
}
return NULL;
}
**Exercice 2:** Gestion d’un Compte Bancaire
Note: Cet exercice doit être rendu avec un snapshot d’exécution.
Dans cet exercice vous allez simuler les dépôts (deposit) et les retraits (withdrawal) effectués sur un compte bancaire fictif. Dans ce cas, les dépôts et les retraits seront effectués par des threads synchronisés. La synchronisation est nécessaire pour deux raisons: (1) l'exclusion mutuelle (mises à jour ne peuvent pas être perdues) et (2) parce que le retrait ne peut pas se produire si le montant de retrait demandé est supérieur au solde actuel du compte. Cela signifie que l'accès au compte (l'objet partagé) doit être synchronisé. Cette application nécessite la coopération et la communication entre les différents threads (threads coopératifs synchronisés). (En d'autres mots, ce problème est similaire au problème du producteur / consommateur où il y a plus qu'un(c à dire plusieurs) producteurs et plusieurs consommateurs actifs en même temps.) Si un thread de retrait tente de retirer un montant supérieur au solde actuel, alors il doit bloquer et attendre jusqu'à ce qu'un dépôt a eu lieu avant de pouvoir essayer à nouveau. Comme nous l'avons traité dans les notes de cours, il faudra que les threads de dépôt signalent tous les threads de retrait d'attente chaque fois qu'un dépôt est achevé.
**1-** Pour garder les choses relativement simples aussi bien que pour voir des résultats immédiats d'une série de transactions (dépôts et retraits), on suppose que les dépôts sont effectués dans des quantités allant de 1 $ à 200 $ et les retraits sont effectués dans des quantités allant de 1 $ à 50 $.
**2-** Vous devriez avoir trois threads de dépôt et quatre threads de retrait d'exécution simultanément.
**3-** Une fois qu'un thread de dépôt a exécuté, le mettre en veille pendant une milliseconde environ (dépend un peu de la vitesse de votre système pour combien de temps vous aurez envie de dormir les discussions des déposants - fondamentalement, nous voulons nous assurer beaucoup plus de retraits que dépôts) pour permettre d'autres threads d’exécuter. C'est la seule situation dans laquelle un thread de dépôt bloque.
**4-** Une fois un thread de retrait a exécuté, il cédera à un autre thread (ne pas le mettre en veille quand même). Cela permettra d'éviter qu’un seul thread de retrait occupe le CPU pour longtemps et exécuter une longue séquence d’opérations de retrait. Les threads de retrait bloquent s'ils tentent de retirer plus que le solde actuel du compte.
**5-** On suppose que tous les threads ont la même priorité.
**6-** Utilisez les mécanismes de synchronisation adéquats pour gérer le blocage, la signalisation, etc.
**7-** La sortie de votre programme doit ressembler à la figure suivante.

/\*FIN\*/