Cours 11, Partage du temps de microprocesseur et RTOS
Q11.1 Qu'est-ce qu’un système d’exploitation?
Un programme permettant à l’usager et au programmeur de gérer efficacement les ressources
du système microprocesseur.
Q11.2 Quelle est la différence entre un système d’exploitation préemptif et un système
d’exploitation non-préemptif?
Le système d’exploitation préemptif interrompt la tâche en cours, puis il décide quelle tâche
sera exécutée entre l’interruption présente et la prochaine interruption du système
d’exploitation. Un système d’exploitation non-préemptif charge un programme en mémoire.
Puis, il l’exécute au complet avant de s’attaquer à la tâche suivante.
Q11.3 Comparez ensemble une super-boucle, un système d’exploitation non-préemptif et
un système d’exploitation préemptif. Quels sont les avantages et les désavantages de
chacune de ces approches pour attribuer le temps de CPU aux tâches?
La super-boucle est simple, les tâches sont exécutées en série (la séquence d’exécution des
tâches est connue) et tout le temps de microprocesseur est alloué aux tâches. Cependant, il n’y
a pas de contrôle ou supervision des tâches : si une tâche prend trop de temps de microp
rocesseur ou gèle, les autres tâches sont pénalisées. Il est aussi plus difficile d’insérer des
nouvelles tâches dans une super-boucle, même s’il est tout-à-fait possible de le faire.
Le système d’exploitation non-préemptif a essentiellement les mêmes avantages et
désavantages que la super-boucle. Cependant, il permet d’exécuter de nouvelles tâches (qui
n’étaient pas dans le programme au moment de la compilation) et offre des ressources aux
nouvelles tâches.
Le système d’exploitation préemptif est possiblement le plus efficace par rapport aux
performances du système : les pertes de temps de microprocesseur causés par les délais ou les
attentes après les périphériques sont minimes. En contrepartie, le système est plus complexe,
les tâches sont exécutées selon une séquence qui varie (cela peut créer des erreurs
d’exécution) et le système d’exploitation utilise toujours un peu de temps de microprocesseur
pour gérer les tâches. Enfin, le système d’exploitation préemptif requiert plus de RAM pour
sauvegarder l’information reliées à l’exécution de chaque tâche et pour le pile de chaque
tâche.
Q11.4 Dans un système microprocesseur, quelles sont les responsabilités du système
d’exploitation?
- Gérer le temps de microprocesseur
- Gérer les accès aux périphériques et fournir des routines pour y accéder
- Gérer la mémoire pour les processus
- Gérer les exceptions et les programmes en faute
- Gérer les communications réseaux
- Fournir une interface usager
Q11.5 Un RTOS n’a pas les mêmes critères de performance qu’un système d’exploitation
qui n’est pas temps réel. Cela a plusieurs impacts sur le design du système d’exploitation.
Quelle est la principale différence entre un RTOS et un OS lorsque le système
d’exploitation détermine la prochaine tâche à exécuter? Lorsque le système d’exploitation
alloue de la mémoire?
L’algorithme d’ordonnancement/planification des tâches doit tenir compte des contraintes
temps-réel pour un RTOS. Les tâches exécutées en premier seront les tâches temps-réel, c’est-
à-dire celles que l’on doit exécuter à l’intérieur d’un temps limité afin d’éviter un échec du
système.
L’algorithme d’allocation de mémoire dans un RTOS doit être plus rapide et plus simple que
celui d’un OS afin d’éviter de retarder l’exécution des tâches temps-réel. Le OS aura un
algorithme plus lent qui fera un meilleur usage de la mémoire.
Q11.6 Que fait-on dans une application utilisant une super-boucle pour réduire la
consommation de puissance du microprocesseur?
Il arrive régulièrement que la super-boucle, c’est-à-dire le programme principal, ne soit
exécutée qu’à tous les intervalles de temps prédéfinis lorsque le système est inactif. On met
une function sleep exécute à chaque boucle de main qui réduit ou coupe l’horloge du
processeur.
Q11.7 Comment fait un système d’exploitation préemptif pour s’assurer de ne pas allouer
de temps à une tâche qui attend ou à une tâche bloquée, c’est-à-dire en attente d’une
réponse d’un périphérique?
Le système d’exploitation garde en mémoire l’état de chaque tâche. Quand une tâche appelle
une fonction du système d’exploitation pour attendre ou pour accéder à un périphérique, l’état
de la tâche change. Ainsi, le système d’exploitation sait qu’il ne doit pas exécuter la tâche tant
que le délai n’est pas expiré ou que le périphérique n’a pas répondu.
Q11.8 Lorsqu’un processus ou une tâche accède à un périphérique lent, l’état de la tâche
devrait devenir bloqué. Comment le programmeur doit-il indiquer au système d’exploitation
que la tâche qu’il a programmée est maintenant en attente d’un périphérique?
Dans la mesure du possible, le programmeur n’a pas à indiquer au système d’exploitation que
sa tâche est bloquée : le programmeur appelle une fonction du système d’exploitation pour
accéder au périphérique et cette fonction met la tâche dans l’état bloqué.
Q11.9 Lorsqu’une tâche appelle une fonction du système d’exploitation pour attendre
(exemple : void OS_Wait(int Xms)), le système d’exploitation met la tâche dans l’état “en
attente”. Habituellement, quel évènement permet de sortir de cet état?
Le système d’exploitation gère le temps dans l’interruption du système d’exploitation. À
toutes les interruptions du système d.exploitation, il regarde si une tâche a fini d’attendre et
ajuste l’état de la tâche en conséquence.
Q11.10 Qu'est-ce qu'une section critique dans un programme?
Une section critique est une portion de code qui doit s’exécuter de façon atomique parce
qu’elle accède à une section de mémoire ou à un périphérique partagée entre plusieurs
threads. Il ne doit absolument pas y avoir plus d'un thread simultanément. Dans le cas d'un
SMI, lagestion des sections critiques est particulièrement importante entre le main et les
interruptions.
Q11.11 Un programmeur crée une fonction F() traitant une variable globale MaVar. La
fonction F() est appelée à chaque exécution de la boucle du main. De plus, la fonction F()
est appelée lors de l'interruption du timer0. Est-ce que ces opérations sont valides? Si elles
sont valides, pourquoi? Si elles ne sont pas valides, comment régler le problème?
La fonction F() n'étant pas réentrante, il risque d'y avoir des conflits sur MaVar. La solution
dans ce cas serait d'utiliser un processus de sémaphores pour l'exécution la fonction F() ou
pour tout changement sur MaVar, permettant ainsi d'éviter le conflit.
Q11.12 Un programmeur doit coder une machine à états appelant différentes fonctions
possédant le même type de retour et les mêmes paramètres pour chaque état. Exemple :
switch(FunctionAExecuter)
{
case ExecuteFunction1 :
Function1();
Break;
case ExecuteFunction2 :
Function2();
Break;
case ExecuteFunction2 :
Function3();
Break;
}
Cependant, dans le but d'alléger le code, il souhaite éviter d'utiliser un switch-case ou une
série de if imbriqués pour déterminer la fonction à appeler dans son main par rapport à
l'état actuel. Quelle autre solution peut-il employer? Décrivez brièvement cette solution.
Il peut utiliser un pointeur de fonction global. Ce pointeur de fonction pourra être modifié par
chaque fonction pouvant s'exécuter pour déterminer l'état suivant. Ainsi, il n'y a qu'à appeler,
dans le main, ce pointeur de fonction, qui exécutera la fonction nécessaire à l'état en cours.
Q11.13 Décrivez le principe d'utilisation des sémaphores et mutex.
Ce principe comporte d'abord une opération de test qui permet de vérifier si une ressource est
disponible et par la suite, l'obtenir si tel est le cas. La vérification et l’obtention de la
ressource ne peuvent être interrompues par d’autres tâches. Lorsque la ressource est obtenue,
la ressource est utilisée, et, ensuite, une opération propre aux sémaphores et mutex permet de
libérer la ressource.
Q11.14 Un système d’exploitation préemptif exécute à tour de rôle les tâches 1 et 2 telles
qu’implémentées ci-dessous. Les deux tâches appellent une fonction pour lire une mémoire
EEPROM SPI:
Tâche 1 Tâche 2 Fonction d’accès à la mémoire
void Tache1(void)
{
short a;
InitT1();
while(1)
{
...
if(evenement1())
{
a= LireEEPROMSPI(20);
}
}
}
void Tache2(void)
{
short d;
InitT1();
while(1)
{
...
if(evenement2())
{
d= LireEEPROMSPI(40);
}
}
}
short LireEEPROMSPI(short adresse)
{
short ValeurLue;
EnvoieOctetSPI(CMD_LECTURE);
EnvoieOctetSPI(adresse >> 8);
EnvoieOctetSPI(adresse & 0xFF);
//Gènère l’horloge SPI pour lire mem.
EnvoieOctetSPI(0);
ValeurLue = REG_SPI_RX*256;
EnvoieOctetSPI(0);
ValeurLue += REG_SPI_RX;
return ValeurLue;
}
Pourquoi l’exécution de ces tâches par le système d’exploitation ne fonctionnera pas?
Supposons que le système d’exploitation interrompt la tâche 1 au milieu de la fonction
LireEEPROMSPI. Si le système d’exploitation exécute ensuite la tâche 2 et que la tâche 2
appelle aussi LireEEPROMSPI, les signaux envoyés à la mémoire seront incorrects.
Q11.15 Lisez et répondez aux questions de SMI_C11_Wait_Avec_OS_Preemptif.pdf (voir
les notes de cours).
Voir SMI_C11_Wait_Avec_OS_Préemptif.pdf.
Q11.16 Expliquez les fonctions GetMutex et ReleaseMutex retrouvée à la fin de
SMI_C11_Notes sur les Mutex.pdf (voir les notes de cours).
Get Mutex :
Si la tâche active a déjà le mutex, on sort de la fonction.
Sinon, la tâche active attend après le mutex :
- Elle vérifie si le Mutex est disponible après avoir désactivé les interruptions
o Si le Mutex est disponible, on le prend et on sort
o Si le Mutex n’est pas disponible, on indique au OS que la tâche attend après le
Mutex (pour que la tâche ne soit pas exécutée inutilement pendant l’attente) et
on attend le Mutex.
Release Mutex :
- On libère le Mutex.
- On remet dans l’état prêt-à-être-exécuté toutes les tâches qui attendaient après le
mutex.
Cours 12 : Compilation, Édition de liens et IDE
Q12.1 Quel est le rôle d'un compilateur?
Le compilateur interprète le texte d’un fichier texte afin de générer le code machine et la liste
de toutes variables/fonctions correspondant au texte. Le compilateur génère un fichier objet
pour chaque fichiercompilé.
Q12.2 Quel est le rôle de l'éditeur de liens?
L’éditeur de lien fait le lien entre les divers fichiers d’un programme afin de créer
l’exécutable. Il vérifie que toutes les variables et fonctions du programme sont définies à
travers tous les fichiers du programme, il place toutes les variables et fonctions en mémoire,
puis il crée l’exécutable.
Q12.3 Que contient un fichier objet? À quoi sert ce type de fichier?
Un fichier objet contient toute l’information nécessaire pour que l’éditeur de lien puisse
insérer la partie de programme contenue dans le fichier à l’intérieur del’exécutable. Le fichier
objet contient donc du code compilé et des symboles indiquant les variableséfonctions
définies dans les fichiers et les variables/fonctions utilisées dans le fichier, mais qui n’y sont
pas définies.
Q12.4 Que contient un fichier exécutable?
Un fichier exécutable contient des informations sur le fichier, le code compilé et toute
l’information nécessaire pour que code puisse être placé en mémoire, puis exécuté. Cela
comprend les besoins en mémoire RAM, l’information sur les librairies à joindre
dynamiquement au code (dll), l’information sur la virtualisation du programme et plus.
Q12.5 Associez chaque opération d'optimisation à un type d'optimisation (haut niveau,
locale, globale, architecturale/dépendante de l'architecture).
Opération Type
Retirer d'une boucle du code qui est
calculé inutilement à chaque itération
Globale
Remplacer les instances d'une variable constante directement apr la constante
Locale
Réarranger les instructions pour améliorer la performance du pipeline Architecturale
Remplacer des procédures par leur co
ntenu (
inlining
Haut niveau
Q12.6 Pourquoi est-il recommandé de vérifier le fonctionnement d'un programme de
nouveau après l'application d'optimisations?
L'optimisation du code apporte des modifications au code écrit par le programmeur. Ces
modifications peuvent découvrir des problèmes latents ou même créer de nouveaux problèmes
pour plusieurs raisons (manque d'information de la part du programmeur, opérations non-
désirées par le programmeur, erreur dans le compilateur, etc).
À noter : la plupart des compilateurs accélèrent le traitement sur les nombres à virgule
flottante en approximant certaines opérations. Généralement, cela amène un gain en
performance sans affecter la qualité du résultat. Or, les librairies de calcul scientifique sont
très sensibles aux erreurs numériques. Dans certains cas, il est très important de spécifier au
compilateur de ne pas optimiser ces opérations pour ne pas fausser les résultats.
1 / 16 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !