Programmation multitâches & OS temps réel
1.0
|
Dans ce TD, il s’agit d’encapsuler la gestion des tâches Posix dans les classes PosixThread
, Thread
, Mutex
et Lock
en s’inspirant du modèle multitâches du langage Java.
Programmez la classe
PosixThread
en vous référant à l’interface de la figure 1a ainsi qu’aux appels Posix du cours ; référez-vous aux manpages des appels Posix suivants pour programmer le 2e constructeur ainsi que les méthodesgetScheduling()
etsetScheduling()
:
pthread_getschedparam()
pthread_setschedparam()
pthread_attr_getschedparam()
pthread_attr_setschedparam()
pthread_attr_getschedpolicy()
pthread_attr_setschedpolicy()
En particulier, on peut utiliser les codes d’erreur renvoyés par la fonction
pthread_getschedparam()
pour tester la validité d’un identifiant de thread.Pour le 2e constructeur, si la tâche Posix n’existe pas, une exception
PosixThread::Exception
devra être produite. Pour les méthodesgetScheduling()
etsetScheduling()
, il faut distinguer les deux cas où le thread est déjà lancé ou pas et les deux méthodes doivent renvoyertrue
si la tâche est active, etfalse
si la tâche n’est pas active.
- Le 2e constructeur
PosixThread(posixId : pthread_t)
s’applique à un pthread déjà existant.
setScheduling()
applique l’ordonnancement et la priorité spécifiée à la tâche (à l’attribut de tâche et à la tâche elle-même si elle est déjà lancée).getScheduling()
renvoie l’ordonnancement et la priorité de la tâche.- pour la méthode
join()
avec timeout, utilisez la fonctionpthread_timedjoin_np()
qui n’appartient pas au standard Posix ;
Programmez la classe
Thread
dérivant dePosixThread
en vous référant à l’interface de la figure 1b ainsi qu’aux éléments du cours. Les méthodesstartTime_ms()
,stopTime_ms()
etexecTime_ms()
doivent renvoyer respectivement les temps absolus de début et de fin d’exécution et la durée d’exécution de la tâche (en millisecondes).
En ce qui concerne la méthode statiquesleep_ms()
, il s’agit juste d’une fonction permettant d’endormir le thread appelant durant le temps spécifié en millisecondes ; testez votre classe en refaisant le TD-2a dans un contexte orienté objets. Imaginez un programme simple permettant de tester tous les aspects de la classe.
Programmez les classes
Mutex
,Mutex::Lock
,Mutex::TryLock
en reprenant les spécifications de la figure 2 et les explications du cours. Prenez note, en particulier, que la classeMutex
contient l’identifiant de condition Posix et que la classe intermédiaireMutex::Monitor
dont héritentMutex::Lock
etMutex::TryLock
porte également les opérations relatives à l’utilisation d’une condition.
Comme type de mutex Posix, choisissez le type récursif.
Testez vos classes en protégeant l’accès au compteur de la question précédente par un mutex.
Complétez la classe
Thread
avec un champ booléenstarted
représentant l’état actif de la tâche ; modifiez votre code de sorte qu’on ne puisse pas relancer une tâche tant que son exécution précédente n’est pas terminée. L’appel destart()
doit renvoyer un booléen :true
si la tâche est effectivement démarrée par l’appel destart()
,false
si la tâche était déjà démarrée au moment de l’appel.
Dans le contexte multitâches, un sémaphore est une « boite à jetons » à accès concurrent :
give()
, on lui rajoute un jeton ;take()
on lui retire un jeton ;take()
est bloquant, avec ou sans timeout ;give()
ne modifie pas son compteur ;0
) ou plein (1
).Programmez la classe
Semaphore
en reprenant l’interface proposée dans le cours et reprise sur la figure 3.
Pour tester votre classe, instanciez un sémaphore initialement vide partagé par 2 types de tâches :
– une tâche productrice qui « donne » des jetons au sémaphore ;
– une tâche consommatrice qui « prend » des jetons au sémaphore ;
dans votremain
, faites tournernCons
tâches consommatrices etnProd
tâches productrices et vérifiez que tous les jetons crées ont bien été consommés.
La figure 4 spécifie l’interface d’une classe template Fifo
. L’appel à pop()
doit être bloquant si la fifo est vide ; l’appel bloquant doit comprendre une version avec timeout.
Programmez la classe
Fifo
en utilisant le conteneur C++std::queue
. Comme il s'agit d'un template, les déclarations et implémentations doivent être dans un seul fichierFifo.hpp
.
Testez la classe en y accédant de manière concurrente par de multiples tâches productrices et consommatrices. Pour cela, utilisez une fifo de nombres entiersFifo<int>
et faites produire par chaque tâche productrice une série d’entiers de0
àn
. Mettez en place un mécanisme pour vérifier que tous les entiers produits par les tâches productrices ont bien été reçus par les tâches consommatrices.