State Machine Implementierung
-
05-07-2019 - |
Frage
Ich bin für einige allgemeine Suche
- Optimierung
- Correctness
- Extensibility
Beratung auf meiner aktuellen C ++ Hierarchical State Machine-Implementierung.
Beispiel
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)
Implementierung
Derzeit wird der HSM als Baumstruktur implementiert, wobei jeder Staat eine variable Anzahl von Staaten als Kinder hat.
Jeder Zustand enthält eine variable Anzahl von „überschreibt“ Blöcke (in einem std :: map) außer Kraft Basiswert. An der Wurzel Zustand weist die Zustandsmaschine einen Satz von Variablen (Funktionen, Eigenschaften ...) zu einigen Standardwerten initialisiert. Jedes Mal, wenn wir geben ein Kind Zustand, eine Liste von „Überschreibungen“ definieren Variable und Werte, die die Variablen und Werte mit dem gleichen Namen in dem übergeordneten Zustand ersetzen sollen. Aktualisiert original für Klarheit.
Referenzierung Variablen
Zur Laufzeit werden die aktuellen Zustände auf einem Stapel abgelegt.
Jedes Mal, wenn eine Variable verwiesen wird, ein nach unten Stapel zu Fuß sucht die höchste Überschreibung durchgeführt wird, oder im Fall von nicht überschreibt, der Standardwert.
Schaltzustände
Jedes Mal, wenn ein einzelner Zustandsrahmen umgeschaltet wird, wird der Zustand auf einen Stapel geschoben.
Jedes Mal, wenn ein Zustand geschaltet wird, ich einen Baum descension verfolgen, die mich aus dem aktuellen Zustand in dem Root-Zustand annimmt. Dann mache ich einen Baum descension vom Sollzustand an die Wurzel Zustand, bis ich die aktuelle Trace entspricht die vorherige Spur zu sehen. Ich erkläre, eine Kreuzung auf, wo diese zwei Spuren entsprechen. Dann, um den Zielzustand zu wechseln, steige I von der Quelle, Zustandsrahmen aus dem Stapel popping bis ich den Schnittpunkt erreichen. Dann habe ich an den Zielknoten aufzusteigen und Zustandsrahmen auf den Stapel schieben.
Also für das Codebeispiel oben
Execution Trace für Leiterschalter
- Quelle state = Aufnahme
-
Ziel State = alsoStreamToRemoteIp
-
descension von source = Recording-> root (trace = [root])
-
descension von target = alsoStreamToRemoteIp-> Wiedergabe-> root (trace = [Wiedergabe root])
-
durchteuft an der Wurzel.
Zum Umschalten von zu alsoStreamToRemoteIp Aufnahme
- Pop „Aufnahme“ aus dem Stapel (und seine Exit-Funktion aufrufen ... hier nicht definiert sind).
- Push „Wiedergabe“ auf den Stapel (und rufen Sie die Enter-Funktion).
- Push "alsoStreamToRemoteIp" auf den Stapel (und rufen die die Enter-Funktion).
Lösung
Zwei Dinge:
. 1: Für die meisten Fälle stellen nur den Zustand Ihres Programms als Model, und mit ihm interagieren direkt oder über das MVC-Muster
2: Wenn Sie wirklich eine FSM benötigen, das heißt Sie wollen zufällig eine Reihe von Aktionen zu Ihrem Modell machen, von denen nur einige zu bestimmten Zeiten erlaubt sind. Dann ....
haltenStill den Zustand Ihres Programms in einem Modell (oder mehrere Modelle je nach Zersetzung und Komplexität) und repräsentieren Zustände und Übergänge mögen.
class State:
def __init__(self):
self.neighbors = {}
Wo Nachbarn ein Wörterbuch von {Action: State}
enthält, so dass Sie so etwas wie
someAction.execute() # Actions manipulate the model (use classes or lambdas)
currentState = currentState.neighbors[someAction]
Oder sogar kühle, haben eine Endlosschleife zufällig eine Aktion von den Nachbarn der Auswahl, Ausführung es, und auf unbestimmte Zeit Zustand zu bewegen. Es ist eine gute Möglichkeit, Ihr Programm zu testen.
Andere Tipps
Ich bin mir nicht sicher, ob ich alle Details folgen hier. Allerdings scheint es, dass Sie einen FSM (Finite State Machine) Implementierung beschreiben, wo Sie mehrere Zustandsmaschinen haben. Manchmal, wenn ein bestimmtes Ereignis (E1) tritt in einem bestimmten Zustand (S1) von FSM F1, müssen Sie eine neue FSM eingeben (nennen wir es F2) insgesamt um die Verarbeitung zu vereinfachen).
Wenn das der Fall ist, dann, wenn E1 in S1 auftritt, müssen Sie eine Aktion Routine aufzurufen, die das Ereignis Lesen übernimmt und implementiert die F2 FSM. Wenn es aufgerufen wird, startet er die Verarbeitung in dem Startzustand von F2 und verarbeitet die jeweiligen Teilveranstaltungen. Wenn es seinen Endzustand erreicht hat, beendet der Dolmetscher für F2. Es könnte einige Informationen an die F1 Aktionsroutine zurück, die ausgesetzt wurde, während F2 lief, und der nächste Zustand in der Formel 1 kann davon betroffen sein.
Der Rest der Beschreibung - Sachen wie ‚Blockierungen überschreiben.‘ - nicht viel Sinn für Menschen ohne Zugang zu Ihrer Implementierung machen