Programmation multitâches & OS temps réel
1.0
|
Cet exercice est destiné à produire des fonctions et opérateurs permettant une utilisation simplifiée de la structure timespec
représentant la mesure des temps dans l’API Posix. Pour accéder à cette structure, vous devez inclure le header time.h
. Dans toutes les fonctions suivantes, les variables de type timespec
résultant d’un calcul doivent être normalisées avec les contraintes suivantes:
tv_sec
(de type time_t
) peut prendre des valeurs négatives tv_nsec
(de type long
) doit être positif ou nul et toujours inférieur à 1000000000
(109) et ce, même pour un temps globalement négatif. Déclarez et implémentez les fonctions suivantes permettant de convertir des
millisecondes
entimespec
et vice-versa:
Déclarez et implémentez les fonctions suivantes permettant respectivement d'obtenir le temps courant et l'opposé d'un temps:
Déclarez et implémentez les fonctions suivantes permettant respectivement d’ajouter et de soustraire deux
timespec
:
En utilisant la fonction Posix
nanosleep()
, déclarez et implémentez la fonction suivante permettant d’endormir la tâche appelante durant le temps spécifié; attention, il faut gérer l’éventualité où l’appel denanosleep()
soit interrompu (voirman nanosleep
):
En utilisant les fonctions ci-dessous, déclarez et implémentez les opérateurs ci-dessous afin de pouvoir utiliser les variables
timespec
comme des scalaires:
Écrivez un programme
main()
permettant de tester toutes ces fonctions.
Pour cette question, reportez-vous aux explications du cours sur les timers Posix avec callback.
Implémentez un timer Posix périodique de fréquence 2 Hz imprimant un message avec la valeur d’un compteur régulièrement incrémenté.
Le programme doit s’arrêter après 15 incrémentations.
On considère la fonction de signature : void incr(unsigned int nLoops, double* pCounter)
. Cette fonction doit effectuer une boucle incrémentant de 1.0
la valeur du compteur pointée par pCounter
elle doit effectuer cette boucle nLoops
fois.
Écrivez le code de cette fonction.
La signature standard du point d’entrée d’un programme est : int main(int argc, char* argv[])
. Le paramètre argc
indique le nombre de chaines de caractères de la ligne de commande ayant lancé l’exécution du programme ; le paramètre argv
est le tableau de l’ensemble de ces chaines dans l’ordre où ils ont été tapés sur la ligne de commande, argv[0]
étant le nom du programme, argv[1]
son 1er paramètre, argv[2]
son 2e paramètre, etc. Ici, la fonction main
doit :
– déclarer une variable nLoops
et l’initialiser avec la valeur numérique décimale de argv[1]
;
– déclarer un compteur counter
de type double
et l’initialiser à 0.0
;
– appeler la fonction incr
sur ces deux variables ;
– imprimer à l’écran la valeur finale de counter
.
Écrivez, compilez et exécutez le programme ainsi défini. Notez la valeur finale du compteur
counter
.
En utilisant des fonctions
timespec_*
développées dans l'exercice (a), affichez à la fin du programme le temps d’exécution de la fonctionincr
en secondes sous la forme d’un nombre à virgule.
On reprend la fonction incr
définie ci-dessus et on la modifie en lui rajoutant un 3e paramètre et une valeur de retour :
unsigned incr(unsigned int nLoops, double* pCounter, bool* pStop)
.
Comme avant, cette fonction effectue dans sa boucle principale une incrémentation de 1.0
de la valeur du compteur passé en paramètre ; la différence avec l’implémentation précédente est que la condition d’arrêt peut être atteinte avant d’avoir effectué le nombre maximal de boucles (nLoops
), dans le cas où le paramètre pointé par pStop
passe à la valeur true
. Sa valeur de retour est le nombre de boucles effectuées (≤ nLoops
).
Modifiez l’implémentation de la fonction
incr
conformément aux indications ci-dessus.
Ce paramètre pStop
est destiné à effectuer des mesures du nombre de boucles effectuées par la fonction incr
durant des temps d’exécution bien déterminés :
– on déclare dans le main
une variable booléenne stop
initialisée à false
et dont on passera l’adresse en paramètre de incr
en tant que pStop
;
– avant d’appeler incr
, on initialise nLoops
à sa valeur maximale possible (utilisez la constante UINT_MAX
définie dans le header standard <climits>
) ;
– on lance un timer sur un temps bien défini (par exemple 1 seconde) avec un callback dont la fonction est de faire passer la valeur de stop
à true
: la boucle de incr
s’arrêtera alors et renverra le nombre de boucles effectuées durant ce temps.
Que faut-il modifier dans la déclaration de
pStop
?
Soit l(t) le nombre de boucles effectuées par la fonction incr
durant l’intervalle de temps t ; on suppose que cette fonction est affine : l(t)=a×t+b. Soit iLoop
la variable comptant la boucle dans la fonction incr
(dans l’expression for(iLoop=0 ; iLoop < nLoops ; ++iLoop)
)
Implémentez une fonction
calib
établissant les valeurs de a et b en mesurant la valeur deiLoop
pour 4 secondes et pour 6 secondes.
Vérifiez par programme (en utilisant la fonctionclock_gettime
vue ci-dessus que votre calibration est correcte.
Imaginez des solutions pour améliorer la précision la fonction l(t) :
– en effectuant plus de mesures
– en vous assurant que l’exécution de la fonctioncalib
ne puisse pas être perturbée par d’autres tâches.