« Par ma foi ! il y a plus de quarante ans que je dis de la prose sans que j'en susse rien, et je vous suis le plus obligé du monde de m'avoir appris cela. »
Bonsoir Marc-Henri,
Comme le dirai Monsieur Jourdain, je viens de découvrir que je fais du thread sans le savoir ! Si, en fait et je donne un exemple :
Dans un programme Arduino, il y a le Setup() qui est éxécuté une seule fois en premier, puis la Loop() qui est éxécutée ensuite de façon répétitive. C'est exactement comme un while(1) { ………}. Le compilateur l'ajoute subrepticement sans qu'on le voit !
Quand je programme mon gestionnaire de réseau, je fais donc éxécuter dans la Loop(), toute une série de tâches qui ne vont occuper le processeur qu'une petite fraction du temps en le libérant le plus vite possible, pour que la suivante prenne la main, et ainsi de suite.
Ces tâches sont (dans mon gestionnaire, mais tout le monde reconnaitra des cas qu'il rencontre aussi) :
- Récupération des messages CAN si le flag a été monté par l'interruption. Il faut lire tous les messages CAN reçus sinon l'interruption n'aura plus lieu ensuite. Les messages sont stockés temporairement dans un tampon circulaire.
- Traitement d'UN SEUL message CAN reçu et stocké dans le tampon circulaire (une occupation ou une libération, ou une demande d'itinéraire, de changement d'aiguille ou de mouvement de train.
- Lecture du port série s'il y a des caractères reçus et une action est lancée seulement si une commande complète est reçue (sinon elle est stockée temporairement). Cela sert principalement au Debug pour valider ou non certains affichages ou passer des commandes de simulation
- Lecture des boutons d'un écran tactile : un seul à la fois donne lieu à l'exécution d'une commande
- Toute une série de tâches périodiques se suivent ensuite en testant la valeur de millis() par rapport à des tops d'actions comme le rafraichissement d'affichages, des clignotements de leds, les calculs de durée d'execution (combien de tours de Loop() par seconde pour mesurer la vitesse du programme), des time-out, des pas de simulation (envoyer par exemple une commande lue dans une carte SD toutes les 2 secondes), etc..
- On peut en imaginer d'autres ...
J'ai décrit là 5 types de threads qui sont, en fait, programmés comme des sous-programme (une entrée et une sortie) et qui ne s'interdisent aucune contrainte de programmation.
En particulier le
switch / case est totalement permis et fort heureusement car il faut bien agir en fonction de la commande reçue et une suite de
if ne serait pas agréable. Les Macros ne sont pas obligatoires non plus.
Ces tâches correspondent bien à un gestionnaire de réseau, mais mon Arduino Mega qui commande des aiguilles est fait de la même façon, avec les tâches liées aux messages, mais aussi les commandes des moteurs d'aiguilles qui sont décalées dans le temps d'au moins une 1/2 seconde pour éviter les appels de courant simultanés (j'ai fait sauter un fusible avent cela !)
La seule contrainte est de bien respecter le non-blocage du processeur pendant l'éxécution d'une tâche (pas de delay(), des while() bien contrôlés, des tests sur toutes les limites) et que chaque tâche puisse reprendre la main sans perdre d'événement d'où quelques tests de Debug pour mesurer les temps d'exécution. D'une manière générale, je n'ai jamais eu de surprise (hors bug évidemment).
Voilà comment on fait du thread sans le savoir !
Amicalement