Temps Réel
S4
Noyau temps réel Mtr86-68K
L. BOUHOUCH
2022/2023
PLAN
2
• Services offerts par le noyau temps réel Mtr86-68K
• Structure d’une application Mtr86-68K
• Politique d’ordonnancement dans Mtr86-68K ;
• Création et activation d’instances multiples d’une même tâche ;
SERVICES OFFERTS PAR LE NOYAU TEMPS REEL Mtr86-68K
3
Mtr86 existe sous différentes formes :
Mtr86-Dos : Noyau temps réel dur.
Mtr86-68K pour EID210 : Noyau temps réel dur.
Mtr86-Win32 : Noyau temps réel mou (dans sa forme actuelle)
Mtr86-Win32 Objet : Noyau temps réel mou (dans sa forme actuelle)
Linux-rt (Noyau Linux standard + patch PREEMPT-RT) : Noyau temps réel dur.
Traite :
Gestion des tâches selon un Mécanisme approprié.
Accès concurrent aux données partagées.
Mécanismes de communications.
Mécanismes de synchronisation.
Structure d’une application Mtr86-68K
STRUCTURE D’UNE APPLICATION Mtr86-68K
5
#include "mtr86.h" // Les fichiers à inclure dépendent de la cible ; ici le Mtr86-68K
// Prototype des fonctions – Parfois facultatif, cela dépend de l’emplacement de main() et init()
[TACHE init(void) ;] // Prototype de la tâche init. (Tâche d’initialisation) possédant la plus haute priorité.
// Aucune autre tâche ne s’exécute tant que celle-ci n’est pas terminée ou suspendue
[TACHE T(void) ;] // Prototype de la tache T.
TACHE init(void)
{
// Créer les sémaphores (variables permettent de compter le nombre de tâches endormies ou les réveils en
attente), tubes, et autres mécanismes
//...
// Créer et éventuellement activer les tâches
active(cree(T, 1, 512)) ; // crée et active la tâche T de priorité 1 et 512 octets de pile.
// Suspendre ou terminer la tâche
// La fin de l’application est obtenu par un appel à la primitive mtr86exit(0) dans une tâche quelconque
}
TACHE T(void)
{ // ...
}
main()
{
start_mtr(init, 512) ; // Lance la tâche init avec une taille de pile de 512 octets
}
Mise en évidence de la politique
d’ordonnancement dans le Mtr86-68K
MISE EN EVIDENCE DE LA POLITIQUE D’ORDONNANCEMENT DANS Mtr86
7
#include "mtr86.h"
TACHE T1(void)
{
long i, j ;
// Durant cette séquence T2 et T3 sont arrêtés
printf("T1: actif (priorité 1) et bloque T2 et T3 (priorité 2)\n") ;
for (j=0 ; j<1000000 ; j++) ;
// Remarque : cette séquence alloue le processeur pour un travail inutile (pour peut être effectuer une
// temporisation). Cette façon de procéder gaspille le temps CPU et ne doit jamais être utilisée.
// Durant la séquence suivante T2, T3 sont actifs à chaque appel de dort durant 1 quantum.
printf("T1: Se suspend périodiquement et libère du temps processeur pour T2 et T3\n\n") ;
for(j=0 ; j<250 ; j++)
{
for(i=0 ; i<10000 ; i++) ; // Simuler l'activité de la tâche
dort(1) ; // T2 et T3 actifs durant 1 quantum (≈1 ms)
}
MONITOR // Accès exclusif de T1 à la ressource écran
gotoxy(1,8) ; // Aller à colonne 1 et ligne 8
printf("T1 : Fin Accélération de T2 et T3\n\n") ;
ENDM // Fin accès
} // T1 est arrêté, ce qui alloue le processeur à T2 et T3 : l'affichage est accéléré
MISE EN EVIDENCE DE LA POLITIQUE D’ORDONNANCEMENT DANS Mtr86
8
TACHE T2(void) // T2 est exécutée de façon concurrente avec T3
{ unsigned i, j ;
for(j=0 ; j<300 ; j++)
{
MONITOR // Accès exclusif de T2 à la ressource écran
gotoxy(1, 6) ; // Aller à colonne 1 et ligne 6
cprintf("T2 : j= %d\n", j) ;
ENDM // Fin accès
for(i=0 ; i<1000 ; i++) ; // Simuler l'activité de la tâche
}
} // T2 est arrêté
TACHE T3(void) // T3 est exécutée de façon concurrente avec T2
{ unsigned i, j ;
for(j=0 ; j<500 ; j++)
{
MONITOR // Accès exclusif de T3 à la ressource écran
gotoxy(1, 7) ; // Aller à colonne 1 et ligne 7
cprintf("T3 : j= %d\n", j) ;
ENDM // Fin accès
for(i=0 ; i<300 ; i++) ; // Simuler l'activité de la tâche
}
mtr86exit(0) ; // Le noyau est stoppé. Sortie après start_mtr() //jamais exécuté
}
MISE EN EVIDENCE DE LA POLITIQUE D’ORDONNANCEMENT DANS Mtr86
9
// Tâche d'initialisation. Possède la priorité maximale. Aucune autre tâche ne peut s'exécuter tant que celle-ci
// n'est pas terminée ou suspendue
// La tâche init dans cet exemple crée et active 3 tâches.
// La tâche T1 est la plus prioritaire et préempte le processeur au détriment des tâches T2 et T3.
TACHE init(void)
{
printf("Init debut\n") ;
active(cree(T1, 1, 1024)) ; // Crée et active la tâche T1 ; Priorité 1 ; 1024 octets de pile
active(cree(T2, 2, 1024)) ; // Crée et active la tâche T2 ; Priorité 2 ; 1024 octets de pile
active(cree(T3, 2, 1024)) ; // Crée et active la tâche T3 ; Priorité 2 ; 1024 octets de pile
printf("Init fin\n") ; // A partir d'ici la tâche T1 est lancée en 1er
}
main()
{
// Lance la tâche init avec une taille de pile de 1024 octets
clsscr() ;
printf(" --------------------- Exemple ---------------------\n") ;
start_mtr(init, 1024) ;
}
Création et activation d’instances
multiples d’une même tâche
CREATION ET ACTIVATION D’INSTANCES MULTIPLES D’UNE MEME TACHE
11
Si les tâches effectuent un travail similaire Créer des instances multiples d’une même tâche.
Problème posé : Tâche doit pouvoir s’identifier.
Exemple créant et activant 8 instances d’une même tâche, chacune affichant la valeur d’un
compteur sur un emplacement différent de l’écran.
#include "mtr86.h"
TACHE init(void) ; // PROTOTYPES DES TACHES
TACHE T(void) ;
TACHE init(void)
{
int j ;
dsp_stk() ; // Visualise les consumations en fin de prog
for(j=0 ; j<8 ; j++)
active (cree(T, 2, 1024)) ; // Créer et lance les instances de tâches
dort (cvrtic(10000)) ; // Temporisation : cvrtic convertit les 10000 ms en quantums
mtr86exit(0) ;
}
CREATION ET ACTIVATION D’INSTANCES MULTIPLES D’UNE MEME TACHE
12
TACHE T(void)
{ int j = 0;
int x, y, tache ;
for( ; ; )
{
tache = tache_c() - 2 ; // Lit le numéro de la tâche courante (1er N° = 2)
x = ((tache%10) + 1)*7 ;
y = (tache/10) + 1 ;
MONITOR
gotoxy(x, y+10) ; // Aller à colonne x et ligne y+10
printf("%d\n", j++) ;
ENDM
dort (10) ;
}
}
main() // Tâche principale
{
clsscr() ;
printf("Exemple de création d'instances multiples d'une même tache.\r\n"
"init() crée 8 taches T() identiques, chacune incrémente un compteur et l'affiche sur l'ecran.\r\n"
"Fin au bout d’environ 10s.\r\n") ;
start_mtr(init,1024) ;
}