© D. Mathieu
mathieu@romarin.univ-aix.fr
I.U.T.d'Aix en Provence - Département Informatique
Créé le 13/12/1999 - Dernière mise à jour : 28/02/2000
Programme destiné à montrer que des commutations de tâches
peuvent se produire à n'importe quel moment. Trois exécutions
successives :
Valeur finale de Partage = 613651
Valeur finale de Partage = 696890 Valeur finale de Partage = 606336 |
En fait, on ne sait pas à quel moment la tâche principale récupère la valeur de la variable Partage avant de l'afficher.Une solution est tentée avec Essai02.adb
On ne voit rien jusqu'à Maxi : constant := 100_000;
Remarques :
Essai de résolution du problème en effectuant l'initialisation de la variable Partage avant le lancement des deux tâches, et en affichant son contenu final après la fin des deux tâches.
Programme destiné à montrer que des
commutations de tâches peuvent se produire à n'importe quel
moment. Il faut maintenant Maxi : constant := 10_000_000; pour
voir apparaître le phénomène. Deux exécutions
successives :
Valeur initiale de Partage = 0
Valeur finale de Partage = -1360466 |
et
Valeur initiale de Partage = 0
Valeur finale de Partage = 2080775 |
Il apparaît donc que l'incohérence du résultat est exclusivement due au parallélisme des deux tâches : il doit arriver parfois qu'une tâche n'ait pas le temps de sauvegarder en mémoire le résultat d'un calcul avant que l'autre tâche n'entame elle-même une succession d'opérations. Toutes ses opération sont perdues lorsque la première tâche reprend la main et sauvegarde la dernière valeur qu'elle a calculée.
Programme destiné à montrer que le
problème soulevé dans les programmes Essai01 et
Essai02
ne
provient que du parallélisme : les deux tâches sont ici
sérialisées (exécutées en série, c'est-à-dire
l'une après l'autre). Résultat :
Valeur initiale de Partage = 0
Valeur finale de Partage = 0 |
Programme destiné à montrer que l'encapsulation
d'une donnée dans un paquetage (P_EntierCaché.ads
et P_EntierCaché.adb)
ne la met pas à l'abri des problèmes de partage d'accès
:
Valeur initiale de Partage = 0
Valeur finale de Partage = -1410043 |
=> l'accès à la donnée du paquetage N'EST PAS ATOMIQUE.
Le paquetage P_EntierCaché offre seulement un accesseur Get et un modifieur Set, ainsi que les deux fonctions Incrementer et Decrementer. On peut donc espérer que la donnée soit protégée, mais ce n'est pas le cas. En fait, chaque tâche exécute successivement les instructions de ce paquetage mais peuvent être interrompues à tout moment, comme précédemment.
Remarques :
Programme destiné à illustrer l'utilisation
d'un type tâche avec discriminant. Un vecteur de deux tâches
est créé avec le même discriminant => il est impossible
de différencier les éditions en provenance de ces deux tâches.
Affichage obtenu :
La tache 1 vous dit Coucou
La tache 2 vous dit Coucou La tache 3 vous dit Coucou La tache 3 vous dit Coucou La tache 2 vous dit Coucou La tache 3 vous dit Coucou La tache 3 vous dit Coucou La tache 3 vous dit Coucou La tache 3 vous dit Coucou |
Remarques :
Programme illustrant la possibilité d'utiliser
un champ de type tâche dans un article. Ce programme provoque l'affichage
suivant (variable si plusieurs executions successives) :
La tache 2 vous dit Coucou
R2.I = 3 La tache 2 Tache cadre achevee vous dit Coucou La tache 2 vous dit Coucou
|
Remarques :
Programme de test de l'identification d'une tâche.
Ce programme provoque l'affichage suivant (par exemple)
:
La tache coucou_0244D378 vous dit Coucou
La tache coucou_0244D378 vous dit Coucou Je suis la tache cadre : main_task_024449B0 Ma tache fille est : coucou_0244D378 La tache coucou_0250160 vous dit Coucou
|
Remarques :
Programme illustrant l'utilisation de l'attribut d'une tâche : lors de l'élaboration d'une tâche (il s'agit içi de la tâche Coucou de type T_TskCoucou), celle-ci reçoit un attribut initialisé à une valeur initiale, elle-même fixée lors de l'instanciation du paquetage générique Ada.Task_Attributes. Au cours de l'exécution de cette tâche, son attribut peut être modifié par elle-même (voir --1) ou par une autre qui la connaît (voir --2). La valeur initiale est cependant conservée et peut être rechargée à tout moment par la procedure Reinitialize (voir --3).
Ce programme provoque l'affichage suivant (chronogramme
indispensable pour suivre):
La tache coucou_0245D378 d'attribut A vous dit Coucou
La tache coucou_0245D378 d'attribut A vous dit Coucou La tache coucou_0245D378 d'attribut C vous dit Coucou La tache coucou_02460160 d'attribut A vous dit Coucou
|
Remarques :
Ce programme illustre que ce sont bien les tâches appelant un point d'entrée d'un objet qui exécutent le code de l'objet et non une autre tâche.
Ce programme résout le problème envisagé plus haut en utilisant un objet protégé.Il utilise pour cela le paquetage P_ProtEntier (fichiers P_ProtEntier.ads et P_ProtEntier.adb) très ressemblant au paquetage P_EntierCaché étudié précédemment, mais qui marche !
Il provoque l'affichage suivant (après quelques
minutes)
Valeur initiale de Partage = 0
Valeur finale de Partage = 0 |
Programme de réalisation d'un rendez-vous par l'intermédiaire d'un objet protégé.
Le paquetage P_Tsk_BAO offre les outils suivants :
1.002000000 : La tache t_tsk_promeneur_02460150 arrive au Rendez-vous
1.502000000 : La tache t_tsk_promeneur_02462F28 arrive au Rendez-vous 2.003000000 : La tache t_tsk_promeneur_02465D00 arrive au Rendez-vous 2.504000000 : La tache t_tsk_promeneur_02468AF8 arrive au Rendez-vous 2.504000000 : La tache t_tsk_promeneur_02460150 repart 2.504000000 : La tache t_tsk_promeneur_02462F28 repart 2.504000000 : La tache t_tsk_promeneur_02465D00 repart 2.504000000 : La tache t_tsk_promeneur_02468AF8 repart 3.005000000 : La tache t_tsk_promeneur_0246B8D0 arrive au Rendez-vous 3.505000000 : La tache t_tsk_promeneur_0246E6A8 arrive au Rendez-vous 4.006000000 : La tache t_tsk_promeneur_02468FD0 arrive au Rendez-vous 4.507000000 : La tache t_tsk_promeneur_02469560 arrive au Rendez-vous 4.507000000 : La tache t_tsk_promeneur_0246B8D0 repart 4.507000000 : La tache t_tsk_promeneur_0246E6A8 repart 4.507000000 : La tache t_tsk_promeneur_02468FD0 repart 4.507000000 : La tache t_tsk_promeneur_02469560 repart 5.007000000 : La tache t_tsk_promeneur_02469AD8 arrive au Rendez-vous |
Remarques :
8.022000000 : La tache t_tsk_promeneur_024661B8 arrive au Rendez-vous |
alors que 14 * 0.5 + 1 = 8 secondes. Ce problème est traité dans le fichier Essai09B.adb.
Programme de réalisation d'un rendez-vous
par l'intermédiaire d'un objet protégé : voir fichier
Essai09A.adb.
La dernière ligne affichée est :
8.002000000 : La tache t_tsk_promeneur_024661B8 arrive au Rendez-vous |
et on constate que la dérive augmente jusqu'à 0.009 secondes, après quoi le nouveau temps est réajusté. Rappel : le "granule" de temps est garanti inférieur à 20 millièmes de seconde = Duration'Small.
Ce programme montre qu'une exception levée et interceptée à l'intérieur du corps d'une tâche fille n'affecte en rien ni le déroulement des autres tâches filles, ni celui de la tâche cadre.
Ce programme montre qu'une exception levée et non interceptée à l'intérieur du corps d'une tâche fille NE SE PROPAGE PAS à la tâche cadre.
Ce programme montre que, quel que soit le nombre de tâches filles dont l'élaboration échoue, UNE SEULE EXCEPTION Tasking_Error est reçue par la tâche cadre.Les autres tâches continuent normalement.
Ce programme montre que l'exception levée dans le corps de la classe fille, même créée dynamiquement dans la partie déclarative, est interceptée par le traitant d'exception de la tâche cadre.
Ce programme illustre l'arrêt d'une tâche pendant un rendez-vous. Dans la deuxième partie, l'exception levée dans le accept du serveur est interceptée par le serveur et le client
Il s'agit de communiquer un délai à la tâche lors de son élaboration. Attention : le type Duration n'étant pas un type discret, il est impossible d'initialiser directement le délai.
Si plusieurs tâches semblables doivent recevoir des valeurs initiales distinctes, elles ne peuvent pas être créées dans un tableau. Elles doivent être créées dynamiquement, à chacune étant passé un indice pointant dans un vecteur de valeurs initiales. Cette solution est très inélégante.
Cette solution utilise un discriminant dont la valeur par défaut n'est pas une constante, mais le résultat d'une fonction évaluée lors de l'élaboration de la tâche, et qui renvoie un indice dans le tableau des valeurs initiales. Cette solution, due à J. Barnes, est plus élégante que la précédente.
Le programme utilise un pointeur d'article pour passer l'ensemble des paramètres à une tâche lors de son initialisation.
Ce programme illustre l'utilisation d'un serveur concurrent. La notion de serveur concurrent est développée dans le cours correspondant. La déclaration et le corps de la tâche TskServeur sont développés dans les fichiers P_Serveur.ads et P_Serveur.adb.
Le chronogramme suivant est obtenu :
-- 0---1---2---3---4---5---6---7---8---9--10--11
-- B1 ----ASSSSSSS-------------------------------- -- B2 ----A-------------------------------SSSSSSSS -- N1 --------A-----------SSSSSSSS---------------- -- U1 --------A---SSSSSSSS------------------------ -- U2 ------------------------A---SSSSSSSS-------- |
où Bx, Nx et Ux désignent les tâches clients de priorité Basse, Normale et Urgente, A leur arrivée et S lorsqu'elles sont servies.
Le chronogramme suivant est obtenu :
-- 0---1---2---3---4---5---6---7---8---9--10--11
-- B1 ----ASSSSSSS-------------------------------- -- B2 ----A-------------------------------SSSSSSSS -- N1 --------A-----------SSSSSSSS---------------- -- U1 --------A---SSSSSSSS------------------------ -- U2 ------------------------A---SSSSSSSS-------- |
Lorsque le nombre de niveaux de priorité est important, l'instruction select... est remplacée par une boucle infinie.
Le chronogramme suivant est obtenu :
-- 0---1---2---3---4---5---6---7---8---9--10--11
-- B1 ----ASSSSSSS-------------------------------- -- B2 ----A-------------------------------SSSSSSSS -- N1 --------A-----------SSSSSSSS---------------- -- U1 --------A---SSSSSSSS------------------------ -- U2 ------------------------A---SSSSSSSS-------- |
J. Barnes propose une modification pour supprimer l'attente active.
Le chronogramme suivant est obtenu :
-- 0---1---2---3---4---5---6---7---8---9--10--11
-- B1 ----ASSSSSSS-------------------------------- -- B2 ----A-------------------------------SSSSSSSS -- N1 --------A-----------SSSSSSSS---------------- -- U1 --------A---SSSSSSSS------------------------ -- U2 ------------------------A---SSSSSSSS-------- |
Ce programme ne marche pas car la barrière est toujours levée (les conditions sont toujours justes !?*)
Ce programme illustre l'utilisation du point d'entrée d'une tâche comme paramètre de généricité d'un paquetage générique : le paquetage générique P_Tsk_Text_IO exporte la procédure Put_Line qui affiche une chaîne en la faisant précéder de identificateur de la tâche qui demande l'affichage. Pour réaliser cet affichage, elle utilise la procédure d'affichage qui lui est passée en paramètre effectif de généricité. Dans cet exemple, le premier affichage est réalisé par une tâche chargée de l'affichage.
Ce programme illustre les deux possibilités d'appel d'entrée conditionnel.
Ce programme illustre la notion de point de synchronisation entre les tâches filles et leur tâche cadre. En particulier dans le cas où une tâche est créée dynamiquement. Comme on le constate, la tâche cadre ne reprend que lorsque les deux tâches filles du premier bloc sont terminées, qu'elles soient activées dans la déclaration ou dans le corps du bloc. En revanche, la tâche cadre reprend aussitôt après le second bloc alors que trois tâches filles ont été élaborées et activées dans la déclaration ou le corps du second bloc.
Cet exemple montre que la tâche cadre correspond A LA PORTEE DU TYPE POINTEUR et non à celle des pointeurs eux-mêmes ou du type tâche.
Le programme suivant montre
Remarques :
-- Temps ecoule (en Secondes) :
1
-- Temps ecoule (en Secondes) : 5 -- Temps ecoule (en Secondes) : 11 -- Temps ecoule (en Secondes) : 15 |
© D. Mathieu
mathieu@romarin.univ-aix.fr
I.U.T.d'Aix en Provence - Département Informatique