Aller au contenu

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);
}
Dans ce code, la fonction 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?

button_polling.cpp
#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

queue_in.hpp
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};
};
garantit le fait qu’un consommateur ne pourra pas consommer de données si aucune donnée n’est disponible dans la Queue ? Si non, est-ce que le sémaphore inSemaphore_ peut être utilisée dans ce but ? Si non, quel mécanisme faut-il mettre en place ?

Mutex réentrant

Exercice 11

mutex_composition.hpp
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_;
};
Dans le code ci-dessus, il est admis que les méthodes 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 thread dans l’objet partagé.
  • La méthode getData bloque tant que la donnée n’est pas mise à jour.
  • La méthode setData débloque la méthode getData.

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.