Dans ce qui suit, il s’agit d’établir un point de synchronisation entre N
threads, simulant des activités que nous appellerons des passants.
L’activité de chaque passant (thread) est composée de trois parties :
-
le traitement T1()
à exécuter avant d’atteindre le point de synchronisation,
-
l’arrivée au point de synchronisation, et l’attente que les N
thread aient atteint ce point,
-
le traitement T2()
à exécuter après avoir quitté le point de synchronisation.
Les traitements T1()
et T2()
seront simplement simulés par des attentes (appels de sleep()
).
Travail à effectuer
Créer le projet RDV_NThreadsBoost
.
Télécharger les fichiers SleepChronogram.h et SleepChronogram.cpp.
Version a
Dans l’espace de noms anonyme du fichier RDV_NThreadsBoost.cpp
, écrire la fonction RendezVous()
, de profil
void RendezVous ();
qui est appelée par chaque thread lorsqu’il arrive au point de rendez-vous.
Cette fonction doit utiliser :
-
un compteur de threads encore attendus (variable globale initialisée au nombre total de threads et décrémentée chaque fois qu’un thread arrive au RDV),
-
une variable-condition qui bloque les threads tant que le compteur n’est pas nul et qui libère ensuite tous les threads bloqués (broadcast).
Dans l’espace de noms anonyme du fichier RDV_NThreadsBoost.cpp
, écrire la classe (ou la struct
) CPassant
, qui contient :
-
un identifiant (entier naturel) qui s’incrémente automatiquement à chaque création d’un CPassant
(utiliser une variable statique),
-
les caractéristiques de fonctionnement d’un thread : le temps qu’il met à arriver au point de rendez-vous, et le temps qu’il met à se terminer après être reparti du point de rendez-vous.
-
l’operator()
qui représente le comportement de chaque passant.
Le corps de cette fonction est composé de trois parties :
-
l’arrivée au point de rendez-vous (sleep()
),
-
le blocage au point de rendez-vous (RendezVous()
),
-
le départ du point de rendez-vous(sleep()
).
Ajouter un vector
de CPassant
s.
Dans la fonction main()
, lire au clavier le nombre de threads à lancer puis, pour chacun, les délais d’arrivée et de départ (on entrera ces données dans un fichier texte qui sera redirigé sur l’entrée standard du programme).
Ces délais sont placés dans une instance de CPassant
, qui est ensuite rangée dans le vector
.
Affichage : afin de suivre le chronogramme du déroulement des opérations, nous vous proposons ici d’utiliser une visualisation plus agréable que de faire afficher des tops d’horloge : à chaque seconde, chaque thread affiche son état (une lettre par exemple) sur une ligne qui lui est propre : le thread 1
progresse sur la ligne 1, le thread 2
progresse sur la ligne 2
, etc.
Il n’affiche rien lorsqu’il est bloqué (sur un sémaphore, dans une variable condition, etc.)
En utilisant le fichier de données
StdIn
suivant
qui contient :
3
3 5
4 6
5 2
redirigé sur l’entrée standard de l’exécutable RDV_NThreadsBoost
qui est mis à votre
disposition et que vous devez
télécharger
(mais cela ne fonctionne pas), vous obtiendrez les chronogrammes suivants (à deux instants différents) :
AAA
AAAA
AAAA
Trois passants (threads) ont été lancés en même temps.
Le symbole 'A'
est affiché à chaque seconde pendant que le thread A
rrive vers le point de rendez-vous.
On voit que le thread 1
est bloqué alors que les deux autres ont continué à progresser pendant 1 seconde.
AAADDDDD
AAAADDDDD
AAAAADDX
On voit sur ce chronogramme que les trois threads sont repartis lorsque le troisième est arrivé au rendez-vous (au bout de 5 secondes).
Chacun a alors repris son exécution normale (D
épart).
Le troisième s’est terminé au bout de 2 secondes (X
), les autres continuent depuis 4 secondes.
Pour obtenir ces affichages, vous devez utiliser la NTCTS clrscr
, la classe gotoxy
et la fonction SleepChronogram()
, toutes trois décrites dans le fichier SleepChronogram.h
.
Version b
Modifier la fonction RendezVous()
pour effectuer un réveil en cascade.
Version c
La bibliothèque Boost offre la fonction barrier
qui permet de réaliser très simplement un rendez-vous de N threads !
La mettre en oeuvre.