Dans une architecture pilotée par les événements, chaque composant agit uniquement lorsqu'un événement est envoyé via le système.
Imaginez une voiture hypothétique avec une pédale de frein et un feu stop.
- Les tours de lumière de frein sur quand il reçoit un brake_on événement, et au large quand il reçoit un brake_off événement.
- La pédale de frein envoie un événement brake_on lorsqu'elle est enfoncée et un événement brake_off lorsqu'elle est relâchée.
C’est très bien jusqu’à ce que la voiture soit allumée avec la pédale de frein déjà enfoncée . Puisque le feu stop n'a jamais reçu d' événement de freinage , il restera éteint - ce qui est clairement une situation indésirable. Allumer le feu stop par défaut ne fait que renverser la situation.
Que pourrait-on faire pour résoudre ce "problème d'état initial"?
EDIT: Merci pour toutes les réponses. Ma question ne concernait pas une voiture réelle. Dans les voitures, ils ont résolu ce problème en envoyant en permanence l'état. Par conséquent, il n'y a pas de problème de démarrage dans ce domaine. Dans mon domaine logiciel, cette solution utiliserait de nombreux cycles de calcul inutiles.
EDIT 2: En plus de la réponse de @ gbjbaanb , je choisis un système dans lequel:
- la pédale de frein hypothétique, après l’initialisation, envoie un événement avec son état, et
- le feu de freinage hypothétique, après l'initialisation, envoie un événement demandant un événement d'état à la pédale de frein.
Avec cette solution, il n'y a pas de dépendances entre les composants, pas de conditions de concurrence, pas de files de messages à vider et pas de composants "maîtres".
la source
initialize
) contenant les données de capteur nécessaires.Réponses:
Il y a plusieurs façons de le faire, mais je préfère garder un système basé sur les messages aussi découplé que possible. Cela signifie que le système dans son ensemble ne peut lire l'état d'aucun composant, ni aucun composant lire l'état d'un autre (car cela crée des liens spaghetti de dépendances).
Ainsi, alors que le système en fonctionnement se débrouillera tout seul, nous avons besoin d'un moyen d'indiquer à chaque composant de se lancer lui-même, et nous avons déjà une telle chose dans l'enregistrement de composant, c'est-à-dire qu'au démarrage, le système principal doit informer chaque composant qu'il est maintenant enregistré (ou demandera à chaque composant de renvoyer ses détails pour pouvoir être enregistré). C'est à ce stade que le composant peut effectuer ses tâches de démarrage et envoyer des messages comme il le ferait en fonctionnement normal.
Ainsi, lorsque le contact sera démarré, la pédale de frein recevrait un message d’enregistrement / contrôle de la part de la direction du véhicule et renverrait non seulement le message "Je suis ici et travaille", mais elle vérifiait alors son propre état et envoyait le message. messages pour cet état (par exemple, un message de pédale enfoncée).
Le problème devient alors un problème de dépendance au démarrage, car si le feu de freinage n’est pas encore enregistré, il ne recevra pas le message. Ce problème est facilement résolu en mettant tous ces messages en file d’attente jusqu’à ce que le système principal ait terminé sa routine de démarrage, d’enregistrement et de vérification. .
Le principal avantage est qu'aucun code spécial n'est requis pour gérer l'initialisation, sauf que vous devez déjà écrire (ok, si l'envoi des messages pour les événements de pédale de frein se trouve dans un gestionnaire de pédale de frein, vous devrez également l'indiquer lors de l'initialisation. , mais ce n’est généralement pas un problème si vous n’avez pas écrit ce code étroitement lié à la logique du gestionnaire) et aucune interaction entre les composants, à l’exception de ceux qu’ils s’envoient déjà normalement. Les architectures de passage de messages sont très bonnes pour cette raison!
la source
Vous pouvez avoir un événement initialize qui définit les états de manière appropriée lors du chargement / démarrage. Cela peut être souhaitable pour des systèmes simples ou des programmes n'incluant pas plusieurs composants matériels, mais pour des systèmes plus complexes comportant plusieurs composants physiques car vous courez le même risque que de ne pas initialiser du tout - si un événement de "freinage" est manqué ou perdu le long de votre communication système (par exemple, un système basé sur CAN), vous pouvez par inadvertance régler votre système en arrière comme si vous l’aviez démarré avec le frein enfoncé. Plus vous aurez de contrôleurs, comme avec une voiture, plus il est probable que quelque chose manque.
Pour tenir compte de cela, vous pouvez demander à la logique "Frein activé" d'envoyer à plusieurs reprises des événements "Frein activé". Peut-être toutes les 1/100 de seconde ou quelque chose comme ça. Votre code contenant le cerveau peut écouter ces événements et déclencher un «frein» pendant qu'il les reçoit. Après 1 / 10sec de ne pas recevoir les signaux "freinage sur", il déclenche un événement interne "brake_off".
Différents événements auront des exigences temporelles considérablement différentes. Dans une voiture, votre feu de freinage doit être beaucoup plus rapide que votre voyant de carburant de contrôle (où un délai de plusieurs secondes est probablement acceptable) ou d’autres systèmes moins importants.
La complexité de votre système physique dictera laquelle de ces approches est la plus appropriée. Étant donné que votre exemple est un véhicule, vous voudriez probablement quelque chose de similaire à ce dernier.
Quoi qu'il en soit, avec un système physique, vous ne voulez PAS compter sur un seul événement reçu / traité correctement. Les microcontrôleurs connectés sur un système en réseau ont souvent un délai d'expiration «Je suis en vie» pour cette raison.
la source
Dans ce cas, je ne modéliserais pas le frein en tant que simple marche / arrêt. J'enverrais plutôt des événements de "pression de freinage" Par exemple, une pression de 0 indiquerait un arrêt et une pression de 100 serait complètement abaissée. Le système (nœud) envoie en permanence des événements de pression de rupture (à un certain intervalle) au (x) contrôleur (s) en fonction des besoins.
Lors du démarrage du système, les événements de pression commençaient à se déclencher jusqu'à sa mise hors tension.
la source
Si votre seul moyen de transmettre des informations d'état est à travers des événements, alors vous êtes en difficulté. Au lieu de cela, vous devez être capable de:
Le feu stop peut être vu comme un observateur de la pédale de frein. En d'autres termes, la pédale de frein ne sait rien du feu stop et peut fonctionner sans lui. (Cela signifie que toute idée de pédale de frein qui envoie de manière proactive un événement "d'état initial" au feu stop est mal conçue.)
Lors de l’instanciation du système, le feu stop s’enregistre sur la pédale de frein pour recevoir des notifications de freinage, lit également l’état actuel de la pédale de frein et s’allume ou s’éteint.
Ensuite, les notifications de freinage peuvent être implémentées de l’une des trois manières suivantes:
Je préfère la première approche, ce qui signifie qu'à la réception de la notification, le feu stop fera simplement ce qu'il sait déjà faire: lisez l'état actuel de la pédale de frein et allumez ou éteignez lui-même.
la source
Dans un système événementiel (que j'utilise et que j'aime actuellement), je trouve important de garder les choses aussi découplées que possible. Alors, avec cette idée en tête, approfondissons la question.
Il est important d'avoir un état par défaut. Votre voyant de frein prendrait l'état par défaut «éteint» et votre pédale de frein prendrait l'état par défaut «haut». Tout changement par la suite serait un événement.
Maintenant pour répondre à votre question. Imaginez que votre pédale de frein soit initialisée et enfoncée, l'événement se déclenche, mais il n'y a pas encore de feu de freinage pour recevoir l'événement. J'ai trouvé plus facile de séparer la création des objets (où les écouteurs d'événements seraient initialisés) en une étape distincte avant d' initialiser une logique. Cela évitera toutes les conditions de compétition, comme vous l'avez décrit.
Je trouve également délicat d’utiliser deux événements différents pour ce qui est effectivement la même chose .
brake_off
etbrake_on
pourrait être simplifiée_brake
avec un paramètrebool on
. Vous pouvez ainsi simplifier vos événements en ajoutant des données de support.la source
Ce dont vous avez besoin est un événement de diffusion et des boîtes de réception de messages. Une émission est un message qui est publié à un nombre non spécifié d'auditeurs. Un composant peut s'abonner à des événements de diffusion pour ne recevoir que les événements qui l'intéressent. Cela permet le découplage, car l'expéditeur n'a pas besoin de savoir qui sont les destinataires. La table d'abonnement doit être configurée de manière statique lors de l'installation du composant (au lieu de lors de son initialisation). La boîte de réception est une partie du routeur de messages qui joue le rôle de tampon pour conserver les messages lorsque le composant de destination est hors ligne.
L'utilisation des factures pose un problème, la taille de la boîte de réception. Vous ne voulez pas que le système doive conserver un nombre croissant de messages pour des composants qui ne seront plus jamais en ligne. Ceci est particulièrement important avec les systèmes embarqués soumis à des contraintes de mémoire strictes. Pour dépasser la taille limite de la boîte de réception, tous les messages diffusés doivent suivre quelques règles. Les règles sont:
Le nom de la diffusion doit être déclaré pendant l’installation du composant. Si un composant envoie une deuxième diffusion avec le même nom avant que le récepteur ne traite la précédente, la nouvelle diffusion remplace la précédente. Vous pouvez maintenant avoir une limite statique de taille de la boîte de réception, qui peut être garantie de ne jamais dépasser une certaine taille et peut être précalculée en fonction des tables d'abonnement.
Enfin, vous avez également besoin d'une archive de diffusion. L'archive de diffusion est une table contenant le dernier événement de chaque nom de diffusion. Les nouveaux composants qui viennent d'être installés auront dans sa boîte de réception des messages provenant des archives de diffusion. À l'instar de la boîte de réception des messages, l'archive de diffusion peut également avoir une taille statique.
De plus, pour faire face à une situation où le routeur de messages lui-même est hors ligne, vous avez également besoin de boîtes d'envoi de messages. La boîte d'envoi de message fait partie du composant qui contient le message sortant temporairement.
la source