Question

Je cherche un général

  1. Optimisation
  2. exactitude
  3. Extensibilité

Conseils sur la mise en œuvre actuelle de ma machine d'état hiérarchique C ++.

Échantillon

variable isMicOn = false
variable areSpeakersOn = false
variable stream = false
state recording
{
        //override block for state recording
        isMicOn = true //here, only isMicOn is true              
        //end override block for state recording
}
state playback
{
        //override block for state playback
        areSpeakersOn = true //here, only areSpeakersOn = true
        //end override block for state playback
        state alsoStreamToRemoteIp
        {
                //override block for state alsoStreamToRemoteIp
                stream = true //here, both areSpeakersOn = true and stream = true
                //end override block for state alsoStreamToRemoteIp
        }
}

goToState(recording)
goToState(playback)
goToState(playback.alsoStreamToRemoteIp)

Mise en œuvre

Actuellement, le HSM est implémenté sous forme d'arborescence dans laquelle chaque état peut avoir un nombre variable d'états sous forme d'enfants.

Chaque état contient un nombre variable de "remplacement". des blocs (dans un std :: map) qui remplacent les valeurs de base. À l'état racine, la machine à états dispose d'un ensemble de variables (fonctions, propriétés ...) initialisées à certaines valeurs par défaut. Chaque fois que nous entrons dans un état enfant, une liste de "substitutions" définissez les variables et les valeurs qui doivent remplacer les variables et les valeurs du même nom dans l'état parent. Mise à jour de l'original pour plus de clarté.

Référence aux variables

Au moment de l'exécution, les états actuels sont stockés sur une pile.

Chaque fois qu'une variable est référencée, une marche arrière de la pile est effectuée en recherchant le remplacement le plus élevé ou, en l'absence de remplacement, la valeur par défaut.

États de commutation

Chaque fois qu'une trame d'état unique est basculée sur, l'état est placé sur une pile.

Chaque fois que vous passez à un état, je trace une descendance dans l’arbre qui me fait passer de l’état actuel à l’état racine. Ensuite, je descends dans l’arbre de l’état cible à l’état racine jusqu’à ce que la trace en cours corresponde à la trace précédente. Je déclare une intersection à l'endroit où ces 2 traces se rencontrent. Ensuite, pour passer à l'état cible, je descends de la source, en extrayant des cadres d'état de la pile jusqu'à atteindre le point d'intersection. Ensuite, je monte vers le noeud cible et place des cadres d’état dans la pile.

Donc, pour l'exemple de code ci-dessus

Suivi de l'exécution du commutateur d'état

  • Etat de la source = enregistrement
  • État cible = alsoStreamToRemoteIp

  • descension from source = recording- & root: trace (trace = [root])

  • descension from target = alsoStreamToRemoteIp- > lecture- > root (trace = [lecture, root])

  • intersecte à la racine.

Pour passer de l'enregistrement à alsoStreamToRemoteIp,

  1. Pop " enregistrement " depuis la pile (et appelez sa fonction de sortie ... non définie ici).
  2. Appuyez sur " lecture " sur la pile (et appelez la fonction entrée).
  3. Appuyez sur " alsoStreamToRemoteIp " sur la pile (et appelez la fonction enter).
Était-ce utile?

La solution

Deux choses:

1: Dans la plupart des cas, il vous suffit de représenter l'état de votre programme en tant que modèle et d'interagir avec lui directement ou via le modèle MVC.

2: Si vous avez réellement besoin d’un FSM, c’est-à-dire que vous souhaitez effectuer au hasard un ensemble d’actions sur votre modèle, dont certaines ne sont autorisées qu'à certains moments. Alors ....

Conservez toujours l'état de votre programme dans un modèle (ou plusieurs modèles en fonction de la décomposition et de la complexité) et représentez des états et des transitions comme.

class State:
   def __init__(self):
      self.neighbors = {}

Où voisins contient un dictionnaire de {Action: State} , afin que vous puissiez faire quelque chose comme

someAction.execute() # Actions manipulate the model (use classes or lambdas)
currentState = currentState.neighbors[someAction]

Ou même plus cool, ayez une boucle infinie sélectionnant de manière aléatoire une action parmi les voisins, l’exécutant et le déplacement de l’état indéfiniment. C'est un excellent moyen de tester votre programme.

Autres conseils

Je ne suis pas sûr de suivre tous les détails ici. Cependant, il semble que vous décrivez une implémentation FSM (machine à états finis) dans laquelle vous avez plusieurs machines à états. Parfois, lorsqu'un événement particulier (E1) se produit dans un état particulier (S1) du FSM F1, vous devez entrer un nouveau FSM (appelez-le F2) pour simplifier le traitement dans son ensemble).

Si tel est le cas, lorsque E1 apparaît dans S1, vous devez appeler une routine d'action qui reprend la lecture de l'événement et implémente le FSM F2. Lorsqu'il est appelé, il commence le traitement à l'état de démarrage de F2 et gère les sous-événements pertinents. Lorsqu'il atteint son état final, l'interprète de F2 se termine. Cela pourrait renvoyer des informations à la routine d’action F1 suspendue pendant l’exécution de F2, ce qui pourrait affecter l’état suivant dans F1.

Le reste de votre description - des éléments tels que "blocs de substitution" - n'aura aucun sens pour les personnes n'ayant pas accès à votre implémentation.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top