PROFDINFO.COM

Votre enseignant d'informatique en ligne

Introduction aux systèmes temps réel

Que signifie exactement l’expression temps réel?

Bien que cela ne fasse pas encore tout à fait l’unanimité dans la communauté informatique et industrielle, l’expression système temps réel a une signification plus précise que lors de son apparition. Il y a plusieurs définitions du temps réel. Plusieurs d’entre eux sont contradictoires. Malheureusement le sujet est controversé et il ne semble pas y avoir un consensus sur cette terminologie.

  1. La définition d'un système en temps réel (selon Donald Gillies) est la suivante: "Un système en temps réel est un système dans lequel l'exactitude des calculs dépend non seulement de l'exactitude logique du calcul mais également du temps où le résultat est produit. Si les contraintes de synchronisation du système ne sont pas rencontrées, celui-ci sera alors non-fonctionnel."
    D'autres ont ajouté: "Par conséquent, il est essentiel que les contraintes de synchronisation du système soient respectées en toutes situations. Cela exige que le système soit prévisible. Il est également souhaitable que le système demeure fonctionnel même si ce dernier est soumis à une utilisation intensive. "
    Un bon exemple est un robot qui doit prendre un objet sur un convoyeur. L’objet se déplace et le robot a une fenêtre de temps restreinte pour agir. Si le robot est en retard, l’objet ne sera plus là, et le système sera défectueux même si le robot a positionné son outil au bon endroit. Si le robot est en avance, l’objet ne sera pas encore arrivé et le bras du robot pourrait même bloquer la progression de l’objet.
    Un autre exemple est le pilote automatique d’un avion. Les sondes de l'avion doivent sans interruption fournir des données valides au pilote automatique. Si une donnée est manquée ou erronée, le pilote automatique peut hésiter une fraction de seconde et se réajuster. Cependant, si trop de mesure sont manquées ou erronées, le pilote automatique ne sera plus en mesure de contrôler l’avion.
    David Sonnier ajoute cette précision: Dans l'exemple du robot, le système temps réel est qualifié de dur car le non-respect des contraintes de temps est catastrophique. Le système serait qualifié de doux si le non-respect des contraintes de temps impliquerait seulement un ralentissement du convoyeur. Beaucoup des systèmes temps réel développés sont en réalité des systèmes en temps réel doux. Un système temps réel idéal devrait toujours réagir de façon sécuritaire même si l’ordinateur n’a pas été en mesure de faire son calcul dans le délai souhaité.

  2. Parfois, et c'est une erreur, on qualifiera un système de temps réel un système tout simplement rapide. Il est important de préciser que temps réel n'est pas un synonyme de rapide; c'est-à-dire, ce n'est pas le temps de réponse lui-même qui est important (elle pourrait être de l'ordre de secondes), mais du fait qu'un temps de réponse maximum suffisant pour résoudre le problème actuel est garantie par le système. Fréquemment, les algorithmes qui garantissent un temps de réponse maximum sont moins efficace que les algorithmes qui n’offre aucune garantie.

  3. Robert Bristow-Johnson ajoute la distinction suivante dans le cas du traitement des signaux (DSP): Dans un processus en temps réel de traitement de signaux (DSP), les échantillons sont analysés à un rythme supérieur ou égal à leur rythme d’arrivé à l’entré du système.
    Considérez un exemple audio de DSP: si un processus a besoin de 2,01 secondes pour analyser ou traiter 2,00 secondes d’échantillons sonores, il n'est pas en temps réel. Si cela prend 1,99, c'est un processus en temps réel de DSP.
    Le file d’attente à l’épicerie est un exemple de la vie courante. Si la file ne cesse de s’allonger dramatiquement cela signifie que la caissière ne peut fournir à la demande. Ce n’est donc pas un système temps réel dans le sens de cette définition. L’épicerie perdra alors de nombreux clients et devra peut-être même fermer. Cette définition est celle utilisée pour le traitement du son, du traitement d’image, de la vidéo, des appels téléphonique sur Internet, etc.

Différence entre applications temps réel et applications de gestion

Les applications utilisées en milieu industriel sont très souvent des applications temps réel très différentes des applications de gestion à plusieurs points de vue:

 

 

 Application temps réel

 Application de gestion

 

Entrées et
sorties

  • Asynchrones
  • Souvent nombreuses
  • Donnent l’état d’un processus à un moment précis
  • Entrées analogiques et
    sorties de puissance
  • Requièrent un système d’interruptions efficace
  • Synchrones
  • Moins nombreuses
  • Changent à un rythme assez lent dans le temps
  • Formulaires de saisie et rapports

 

 

 

Délais

  • Système déterministe
  • Source technologique (imposés par le matériel)
  • Contraintes de temps sévères
  • Système non-déterministe
  • Source ergonomique (imposée par le confort)
  • Délais moins critiques

 

Environnement

  • Système embarqué
  • Système contrôlant du matériel ou communiquant étroitement avec plusieurs périphériques
  • Hostile aux équipements informatique (poussière, humidité, chaleur …)
  • Doit fournir un interface simple et sûre, permettant à l’utilisateur de réagir promptement
  • Micro-informatique
  • Système pratiquement indépendant du matériel
  • Conditions « idéales »
  • L’utilisateur n’a pas à réagir promptement et est plus centré sur une tâche

 

Fiabilité

  • Une simple erreur de calcul peut souvent être tolérée
  • Un arrêt imprévu du système a des conséquences tragiques
  • Une simple erreur de calcul est souvent fatale
  • Le système peut souvent être arrêté à n’importe quel instant de son exécution sans conséquence grave

 

Architecture de l’application

  • Les traitements sont découpés en plusieurs tâches qui s’exécutent de façon concurrente
  • Les objets logiciels représentent des objets concrets du monde réel (moteurs, capteurs, périphériques)
  • Les traitements sont plus souvent qu’autrement séquentiels
  • Les objets logiciels représentent des objets abstraits du monde réel (comptes, trajets, « clients »)

Les applications industrielles, médicales et militaires sont souvent des applications en temps réel, car elles comportent plusieurs des caractéristiques de la première colonne. Dans l’optique du cours actuel, les applications suivantes ne sont pas des applications temps réel, quoi qu’en dise le langage courant:

Dans ces derniers cas, c’est plutôt l’ergonomie (confort) plutôt que les contraintes technologiques qui commande un temps de traitement rapide. On devrait dans ce cas (pour être plus juste) parler d’application interactive ou à réponse rapide.

Différences entre système d’exploitation temps réel, exécutif temps réel, application temps réel et système en temps réel

Le déterminisme

On a parlé de système déterministe. Que veut-on dire au juste par déterminisme ? En termes simples, le déterminisme d’un système est la propriété qui nous permet de prédire son comportement dans toutes ses situations d’exécution. De façon générale, cette propriété est extrêmement importante dans tous les secteurs de l'informatique. Si le système se met à dérailler de façon imprévisible, il n’est pas déterministe. Demandons-nous si les logiciels distribués à grande échelle sont déterministes… Un guichet automatique (qui n’est pas un système temps réel, mais est un système informatique tout de même) doit être déterministe. Son comportement doit avoir été prévu afin de répondre adéquatement à chaque situation qui se présente. Un tel système informatique doit pouvoir réagir de façon adéquate lorsque l’utilisateur dérobe à la séquence normale des opérations : Entrer la carte, Entrer son NIP, Choisir une opération…. Le système doit en effet pouvoir traiter la séquence d’actions suivantes sans broncher : Entrer la carte, Choisir une opération, Entrer des nombres au hasard… … et le concepteur doit même pouvoir dire dans quel état doit se trouver le système après une séquence donnée d’opérations quelconques.

Dans un système en temps réel, le déterminisme inclut la capacité de prédire le temps d’exécution maximal des tâches impliquées. Il faut savoir à l’avance que telle ou telle séquence d’opération se fera à l’intérieur de tel ou tel délai.

Prenons l’exemple d’un réservoir hermétique muni d’un capteur de pression et d’une soupape de sécurité. Le délai entre la lecture d’une pression trop élevée et l’ouverture d’une soupape de sécurité doit être connu pour savoir si les catastrophes seront toujours évitées. Ici, tous les processus requis, tant matériels que logiciels, doivent avoir été minutés soigneusement avant la mise en marche du système, et dans plusieurs cas de figure. Il est souvent impossible de connaître les délais exacts ; il est important dans ce cas de disposer d’une borne supérieure estimée sur le délai, et de savoir si ce temps maximal de réaction est inférieur au temps que prend la catastrophe pour se produire.
On a donc les relations suivantes entre les délais impliqués, dans le cas des traitements relatifs à une situation donnée :

Pour affirmer qu’un système est déterministe (qu'il respecte ses délais), il faut qu'en tout temps :

t < Test et Test < T

C’est la seule manière de s’assurer que t < T et de garantir que les situations critiques sont prises en charge à temps. Ces calculs sont souvent difficiles à réaliser. Les résultats obtenus dépendent non seulement des algorithmes utilisés dans les traitements, mais de pratiquement tout ce qui a contribué ou contribue au système :

Nous reviendrons sur ces concepts lorsque nous parlerons du traitement des interruptions, qui sont souvent les mécanismes les plus critiques dans un système.

Solutions en boucle

Avant d’en arriver aux systèmes d’exploitation temps réel et exécutifs sophistiqués d’aujourd’hui, les concepteurs de systèmes ont tenté de concevoir des applications qui rencontraient leurs délais à l’intérieur de systèmes monotâches. Il fallait faire en sorte que chaque « tâche » puisse obtenir un peu de temps pour utiliser les ressources du processeur. Un bon moyen de le faire est de concevoir une tâche en boucle - que l'on nomme aussi un exécutif cyclique - qui fait appel à plusieurs sous-programmes. Nous verrons que pour peu que le problème se complexifie, la solution en boucle devient difficile à réaliser.

Le problème du terminal

On écrit une application qui doit simuler un terminal. Des données à afficher proviennent d’un port série RS-232. La seule fonction du terminal est d’afficher les caractères reçus à l’écran, et de diriger les caractères lus au clavier sur le port série. Le port série a une vitesse maximale de 960 caractères par seconde, le clavier, une vitesse maximale de 10 caractères par seconde et l'écran 1000 caractères par seconde. L’illustration donne un bref aperçu du système. On identifie deux tâches indépendantes dans ce système :

 

RecevoirEtAfficherCaracteres()
{
	Si caractère disponible sur le port série
	{
		Lire le caractère sur le port série
		Afficher le caractère à l’écran
	}
}
	
LireEtEnvoyerCaracteres()
{
	Si caractère disponible dans le tampon du clavier
	{
		Lire le caractère dans le tampon
		Écrire le caractère sur le port série
	}
}
	
void main()
{
	while( !Fin ) 
	{
		RecevoirEtAfficherCaractere();
		LireEtEnvoyerCaractere();
	}
}
	

Les tâches se succédent afin que chacune obtienne la possibilité de s’exécuter. Il est important que les fonctions soient non-bloquantes pour laisser la chance à la fonction suivante de s'exécuter. La technique utilisée ici pour déterminer la disponibilité d’un caractère sur le port série ou dans le tampon du clavier est appelé scrutation (en anglais : polling). Dans cette boucle il y a de l'attente active car le processeur est utilisé même s'il n'y aucun échange de caractères. Ce n’est vraiment pas le moyen le plus efficace de procéder si d’autres programmes doivent exécuter sur le même système! En effet, la boucle exécutera en consommant les ressources du processeur, tandis qu’il est possible d’attendre sagement que le système nous avise qu’un caractère est disponible. Cette dernière solution est le mécanisme des interruptions.

Question: Qu'elle est la contrainte de temps de ce terminal?

Puisqu'en un tour de boucle l'exécutif cyclique doit traiter les deux entrées, la boucle doit suivre l'entrée la plus rapide soit le port série. La boucle doit donc s'exécuter au moins 960 fois par seconde. 960 tours par seconde est un fréquence. Le temps étant l'inverse de la fréquence, T = 1/f = 1/960 = 1,04 ms.

La solution en boucle régulée

La vitesse d'exécution de la boucle précédente est difficilement prévisible. On peut réguler la vitesse de la boucle à 1000 tours par seconde (ou 1 ms par tour) à l'aide de la variable TempsEcoule qui sera périodiquement remis à VRAI par une tâche extérieure:
void main()
{
	while( !Fin ) 
	{
		if(TempsEcoule)
		{
			RecevoirEtAfficherCaractere();
			LireEtEnvoyerCaractere();
			TempsEcoule = FAUX; 
		}
	}
}
	
Cette deuxième solution, bien que régulée, a toutes les caractéristiques d'un exécutif cyclique: les fonctions doivent être non-bloquantes, elle utilise la scrutation et il y a de l'attente active sur la variable TempsEcoule.

Avantages et désavantages de la solution en boucle

Avantages:

Désavantages:

La solution multitâche régulée par interruptions

La solution idéale consiste à séparer le problème en deux threads, un exécutif cyclique distincts par thread, et de réguler chacune des boucles à l'aide d'interruptions. Chacune des boucles pourra donc être régulée à des vitesses différentes, la première sera régulée à une vitesse de 1000 tours par seconde (la vitesse maximale du port série étant 960 caractères par seconde) tandis que la deuxième sera régulée à 10 tours par seconde (la vitesse maximale du clavier étant 10 caractères par seconde):

 

RecevoirEtAfficherCaracteres()
{
	Demander au RTOS de générer des interruption à toutes les millisecondes
	while( !Fin ) 
	{
		Si caractère disponible sur le port série
		{
			Lire le caractère sur le port série
			Afficher le caractère à l’écran
		}
		Attendre la prochaine interruption 
	}
}
	
LireEtEnvoyerCaracteres()
{
	Demander au RTOS de générer des interruption à toutes les 100 millisecondes
	while( !Fin ) 
	{
		Si caractère disponible dans le tampon du clavier
		{
			Lire le caractère dans le tampon
			Écrire le caractère sur le port série
		}
		Attendre la prochaine interruption 
	}
}
	
void main()
{
	DémarrerThread( RecevoirEtAfficherCaracteres );
	DémarrerThread( LireEtEnvoyerCaracteres );
	Attendre fin de l'application
}
	

Cette solution a plusieurs avantages:

Mais il faudra prendre garde aux désavantages classiques de la programmation multitâche: