Les systèmes temps-réel durs (hard real-time) doivent exécuter des tâches en
garantissant un borne supérieure sur le pire des cas du temps de calcul
néces-saire à la réalisation de ces tâches (évidemment, il importe aussi de garantir la
fonction et la correction de ces tâches). Ces systèmes sont typiquement enfouis
dans un système physique avec lequel ils interagissent. Il peut s’agir par exemple
d’un système de contrôle et de commande au sein d’un véhicule. Presque
sys-tématiquement, ces systèmes doivent assurer plusieurs tâches en parallèle. En
effet, les systèmes physiques à contrôler sont composés en général de plusieurs
composants, comme différents capteurs (pression, température, position, etc)
ou effecteurs (moteur etc). Donc l’ensemble des opérations que doit réaliser le
système de contrôle est structuré en différentes tâches qui peuvent correspondre
aux fonctions des composants physiques. Ensuite chacune de ces tâches peut être
soumise à des contraintes temps-réel. On qualifie aussi ces systèmes de réactifs
car ils réagissent à leurs entrées pour fournir des sorties adaptées, le tout se
déroulant dans une boucle infinie.
La plateforme d’exécution est souvent un ordinateur ou contrôleur
compor-tant un unique processeur mais les plateformes processeurs (ou
multi-cœurs) se généralisent de plus en plus et apportent des avantages et difficultés
supplémentaires pour la gestion du multitâche. Les processeurs récents tendent
aussi à avoir un comportement difficile à quantifier au pire des cas car les
mé-canismes comme les caches ou les pipelines améliorent surtout les performances
en temps moyen et peuvent connaitre une grande variabilité dans le temps de
calcul.
3.3.1 Approche classique
L’approche classique de la conception de systèmes temps-réel reprend les
techniques de programmation impératives en y rajoutant une discipline et une
théorie permettant d’assurer les contraintes temps-réels. Les systèmes sont donc
mis au œuvre dans un langage de programmation usuel pour l’informatique
em-barqué (typiquement C ou ADA). Chaque tâche à réaliser est affectée à un
pro-cessus. Le tout est exécuté et ordonnancé par un système d’exploitation
temps-réel qui met en œuvre des stratégies d’ordonnancement spécialement étudiées
pour assurer que le comportement temps-réel global respecte toutes les
con-traintes temps-réels locales à chaque tâche. Les tâches peuvent être spécifiées
selon différents modèles selon le contexte et les besoins. Mais les propriétés de
ces tâches comprennent au moins la périodicité, le temps de calcul au pire des
cas et une échéance à respecter. Le calcul d’une tâche doit être terminé avant
l’échéance (prise depuis le début de la période de calcul). Comme le calcul d’une
tâche peut être interrompu à la faveur d’autre tâches par le système
d’ordon-nancement, il est possible que les échéances ne soient pas respectées si la tâche est
interrompue trop longtemps. Les modèles de tâches plus évolués peuvent aussi
considérer des concepts comme des priorités entre des tâches, des dépendances
de communications, etc. Il existe de nombreux algorithmes d’ordonnancement
avec des performances et des capacités variables, chaque algorithme garantit
un ordonnancement correct si un certain critère sur les propriétés des tâches
est vérifié. Ce critère permet de choisir l’algorithme adapté ou de dimensionner
la plateforme d’exécution de manière à garantir un ordonnancement toujours
correct (c’est à dire que les tâches terminent avant leurs échéances).
3.3.2 Approche synchrone
L’approche synchrone est apparue au milieu des années 80 afin de répondre
aux besoins spécifiques et aux particularités que l’on trouve dans la conception
et la mise au point de système embarqué. Pour cela, cette approche propose de
travailler à un niveau abstrait éloigné des considérations matérielles et d’utiliser
un paradigme de programmation déterministe, c’est à dire que le résultat d’un
calcul ne doit être fonction que de ses paramètres (pas d’effet de bord, l’ordre
d’exécution n’a pas d’influence).
Pour cela, le paradigme impératif avec ces variables est abandonné en faveur
de la manipulation de flots de données. Chaque flot de donnés représente
l’évolu-tion d’une valeur au cours du temps, tous les flots d’un programme évoluent en
même temps, d’où le nom de programmation synchrone. Cette approche est en
opposition avec la programmation classique, ou chaque fils d’exécution parallèle
peut changer la valeur de ses variables de manière asynchrone et doit changer
les valeurs variable par variable. Les langages synchrones disposent en général
d’un opérateur pour accéder à la valeur précédente (ou encore avant) du flot de
valeur d’une donnée, un programme synchrone est en fait un système
d’équa-tions déterminant la prochaine valeur de chaque flot en fonction des valeurs
passées et de la valeur courante.
Le but est de faire travailler le programmeur à un niveau d’abstraction proche
du niveau de conception, à ce niveau les temps de calculs et de communications
sont pris comme nuls. Ensuite, l’implémentation est obtenue par un compilateur
qui produit un programme dans lequel on s’assure que le temps d’exécution
est borné et l’hypothèse du synchrone vérifiée en pratique sur une plateforme
matériel donnée.
Plusieurs langages synchrones existent, nous pouvons notament citer :
Lus-tre (que l’on peut trouver dans la suite de logiciel SCADE) voir [20, 26] par
N. Halbwach P. Caspi, P. Raymond et D. Pilaud ; Signal voir [34] par P.
Guer-nic, M. Borgne, T. Gautier, C. Maire et Esterel (qui propose des structures de
contrôle plus proche du style impératif) voir [15] par G. Berry et G. Gonthier.
Ces langagues se prêtent bien à une représentation graphique sous forme de
dia-gramme (ce mode de réprésentation peut être utilisé à la place du code source),
ce qui est proposé notamment par l’outil SCADE.
Un langage synchrone étant principalement destiné à équiper des systèmes
critiques, leur sémantique est spécifiée formellement et il existe différentes théories
et outils pour en assurer la correction (par exemple Lesar (Lustre model checker),
Esterel model checker ansi que des outils contenu dans SCADE).
3.3.3 UML2 et MARTE
Unified Modeling Language(UML) est une norme définissant des diagrammes
destinés à être utilisé lors de la conception de logiciel orienté objet. UML 1.1 a
été accepté par l’Object Management Group en 1997. Cette syntaxe graphique
intègre de nombreux types de schéma provenant de diverses notations en vigueur
à cette époque. Ce n’est pas une méthode de développement, et UML ne précise
donc pas comment doivent être utilisées ses notations.
La version 2.0 a été normalisée en 2005 (puis d’autres révisions mineures)
et introduit une superstructure définissant les définitons d’UML. Utilisant cette
définition par superstructure, la sémantique des diagrammes UML est donné
par un méta-modèle. Bien qu’il existe donc des descriptions de la sémantique
d’UML, celle ci n’est pas complètement formelle et fixée dans la norme. Il
ap-partient à l’utilisateur de la notation de suivre par ailleurs une méthode de
développement. Entre autre chose, UML2 définit un mécanisme de profil qui
permet d’ajouter des notations (toujours graphiques) pour des domaines qui ne
seraient pas couverts par la norme officielle.
C’est ainsi qu’est conçu le profil UML 2Modeling and Analysis of Real Time
and Embedded systems MARTE
1qui est une norme proposée par l’OMG qui
propose des modèles spécialisés dans la conception et de logiciels temps-réel.
Dans le document
Gestion du temps par le raffinement
(Page 47-50)