Exercices du chapitre "Modèles de programmation"
Attentes actives
Exercice 1
Pourquoi n’est-il pas souhaitable d’effectuer des attentes actives (qui occupent le CPU) ?
Ordonnancement de tâches périodiques
Exercice 2
Soit un programme qui contient deux tâches périodiques avec les spécifications temporelles suivantes: C1=400ms, D1=500ms, T1=1000ms, C2=500ms, D2 = 1000ms, T2=1000ms. Esquissez le diagramme temporel d’une période complète de 1000ms, en indiquant toutes les caractéristiques temporelles (C, T, a, s, f, D) pour les deux tâches.
Super-loop et ordonnancement manuel
Exercice 3
Vous devez établir la table des tâches pour le problème ci-dessous et réalisez le programme à l’aide d’un modèle super-loop.
Votre programme comporte deux tâches avec les paramètres T1=1000ms, C1=50ms, T2=1500ms et C2=50ms. La tâche consiste à inverser une LED donnée et le code de la fonction réalisant la tâche est
void task(DigitalOut& led) {
led = !led;
wait_us(50000);
}
wait_us est utilisée afin de simuler un temps de calcul C=50ms.
Etablissez la table des tâches et réalisez le programme à l’aide d’une super boucle. Si la table des tâches comporte des temps d’attente, vous devez réaliser ces temps d’attente en appelant la méthode ThisThread::sleep_for(), qui au contraire de wait_us réalise une attente passive et permet au système d’éventuellement accomplir d’autres tâches.
Ordonnancement statique cyclique
Exercice 4
Trouvez au moins un avantage et un inconvénient supplémentaire inhérent à un système réalisant un ordonnancement statique cyclique.
Détection d’évenement par polling
Exercice 5
Analyser le programme ci-dessous. Que peut-il se passer dans l’exécution du programme suivant concernant le traitement de la pression du bouton?
#include "mbed.h"
int main()
{
DigitalOut led1(LED1);
DigitalIn button(PA_0);
while (true) {
ThisThread::sleep_for(2s);
if (button)
{
led1 = !led1;
}
}
}
Détection d’évenement par interruption
Exercice Exercices du chapitre “Modèles de programmation”/6
Modifier l’exemple de code de l’exercice 5 afin que la pression sur le bouton soit traitée selon le principe d’interruption. Observez la différence de comportement de l’application entre les deux solutions.
Machine d’état
Exercice 7
Considérons le code que nous avons écrit dans le chapitre Machines d’état pour faire clignoter les LEDs. Si on remplace le programme principal par le suivant :
int main()
{
System system;
system.AppendStateMachine(new Led(LED1, 60));
system.AppendStateMachine(new Led(LED2, 45));
system.AppendStateMachine(new Led(LED3, 30));
system.AppendStateMachine(new Led(LED4, 15));
Ticker clock;
clock.attach(callback(&system, &System::Tick), 15ms);
while (true) {
ThisThread::sleep_for(Kernel::wait_for_u32_forever);
}
}
Quelle est la période de clignotement de chacune des 4 LEDs ?
Ce programme n’est pas optimal. Identifiez sa principale faiblesse et corrigez-la.
Race condition
Exercice 8
Imaginez que l’exécution de la méthode getAndPrintDateTime soit
interrompue alors que les valeurs de la variable locale dt ont été
partiellement mises à jour. Dans ce cas, décrivez un problème qui
pourrait mener à une mise à jour erronée de l’horloge.
Il suffit d’ajouter une attente active de 5ms à un endroit donné
afin de reproduire le problème de manière systématique: décrivez
ce changement.
Race condition et mutex
Exercice 9
Modifiez la réalisation de la classe Clock afin de protéger les
accès concurrents aux sections critiques à l’aide d’un Mutex.
Réalisation d’une queue à l’aide de sémaphores
Exercice 10
Comme expliqué, la réalisation d’une Queue nécessite également de contrôler le mécanisme de consommation et non seulement de production. Est-ce que la réalisation ci-dessous
class Queue {
public:
...
void put(int datum)
{
inSemaphore_.acquire();
// insert element in buffer
}
int get(void)
{
// pick element from buffer
inSemaphore_.release();
return datum;
}
private:
...
int buffer_[QUEUE_SIZE] = {0};
...
Semaphore inSemaphore_ {QUEUE_SIZE};
};
inSemaphore_ peut être utilisée dans ce but ? Si non,
quel mécanisme faut-il mettre en place ?
Mutex réentrant
Exercice 11
class A
{
void lock()
{
mutex_.lock();
}
void unlock()
{
mutex_.unlock();
}
private:
//
Mutex mutex_;
}
class B
{
void method1()
{
a_.lock();
...
method2();
...
a_.unlock();
}
void method2()
{
a_.lock();
...
a_.unlock();
}
private:
// owns an instance of A
A a_;
};
method1()
et method2()de la classe B doivent acquérir l’instance de A
afin d’effectuer un ensemble d’opérations qui doivent être atomiques
sur cette instance.
Expliquer pourquoi un deadlock survient si le mutex n’est pas réentrant.
Synchronisation avec moniteur
Vous devez synchroniser à l’aide d’un moniteur (ConditionVariable), une
tâche qui met à jour une donnée dans un objet partagé avec une tâche qui
reprend cette donnée mise à jour pour l’afficher. Il s’agit d’un problème
classique de producteur/consommateur.
Exercice Exercices du chapitre “Modèles de programmation”/12
Créer un objet partagé entre un thread producer et un thread
consumer. La donnée partagée est mise à jour par la méthode void
setData(int value) et relue par la méthode int getData() de l’objet
partagé.
- Le moniteur est caché aux deux
threaddans l’objet partagé. - La méthode
getDatabloque tant que la donnée n’est pas mise à jour. - La méthode
setDatadébloque la méthodegetData.
Proposez une solution qui fonctionne avec plusieurs consommateurs.
Proposez deux options de solutions où les consommateurs affichent les données soit alternativement, soit tous en simultané à chaque mise à jour.