Tutorials zu Zustandsmaschinen [closed]

Lesezeit: 9 Minuten

Benutzeravatar von ant2009
Ameise2009

Ich frage mich nur, ob jemand einige gute Tutorials im Internet für die Entwicklung von Zustandsmaschinen kennt. Oder E-Books?

Ich fange an, an Zustandsmaschinen zu arbeiten und brauche nur etwas Allgemeines, um loszulegen.

  • Siehe auch hier: stackoverflow.com/questions/1647631/c-state-machine-design/…

    – paxdiablo

    30. Oktober 2009 um 5:13 Uhr

Benutzeravatar von qrdl
qrdl

Zustandsmaschinen sind in C sehr einfach, wenn Sie Funktionszeiger verwenden.

Grundsätzlich benötigen Sie 2 Arrays – eines für Zustandsfunktionszeiger und eines für Zustandsübergangsregeln. Jede Zustandsfunktion gibt den Code zurück, Sie suchen die Zustandsübergangstabelle nach Zustand und Rückkehrcode, um den nächsten Zustand zu finden und ihn dann einfach auszuführen.

int entry_state(void);
int foo_state(void);
int bar_state(void);
int exit_state(void);

/* array and enum below must be in sync! */
int (* state[])(void) = { entry_state, foo_state, bar_state, exit_state};
enum state_codes { entry, foo, bar, end};

enum ret_codes { ok, fail, repeat};
struct transition {
    enum state_codes src_state;
    enum ret_codes   ret_code;
    enum state_codes dst_state;
};
/* transitions from end state aren't needed */
struct transition state_transitions[] = {
    {entry, ok,     foo},
    {entry, fail,   end},
    {foo,   ok,     bar},
    {foo,   fail,   end},
    {foo,   repeat, foo},
    {bar,   ok,     end},
    {bar,   fail,   end},
    {bar,   repeat, foo}};

#define EXIT_STATE end
#define ENTRY_STATE entry

int main(int argc, char *argv[]) {
    enum state_codes cur_state = ENTRY_STATE;
    enum ret_codes rc;
    int (* state_fun)(void);

    for (;;) {
        state_fun = state[cur_state];
        rc = state_fun();
        if (EXIT_STATE == cur_state)
            break;
        cur_state = lookup_transitions(cur_state, rc);
    }

    return EXIT_SUCCESS;
}

Ich lege nicht lookup_transitions() funktionieren, da es trivial ist.

So mache ich seit Jahren Zustandsmaschinen.

  • Schön, danke dafür. Der einzige mögliche Fehler hier ist, dass die lookup_transitions mit dieser Übergangstabellen-Datenstruktur wahrscheinlich linear (O(n)) sein werden. Es ist möglich, es mit multidimensionalem Array zu verbessern – garantiert O (1). Z.B. Die Tabelle kann als multidimensionales Array dargestellt werden, wobei der Schlüssel der Status und der Wert ein Array ist, in dem der Schlüssel der Rückgabecode und der Wert der nächste Status ist: int state_transitions[][3] = { [entry] = { foo, end, foo }, ... } /* ok, fail, repeat */

    – Alex

    10. Oktober 2013 um 21:57 Uhr


  • Warum geben Ihre Zustandsfunktionen keine Aufzählung statt Ints für die Suchfunktion zurück? Sie geben einen Ret-Code zurück, nicht wahr?

    – Django

    3. April 2016 um 14:37 Uhr

  • Wäre es nicht viel einfacher, einfach zu haben src_state und dst_state als Funktionszeiger? Ich verstehe den Vorteil nicht, sie vom Enum-Typ zu haben, wenn Sie sie nur verwenden, um einige Funktionszeiger in einem Array nachzuschlagen.

    – Multisync

    17. August 2016 um 0:29 Uhr

  • @Multisync Allgemein gesagt, state != function, es ist üblich, mehrere verschiedene Zustände zu haben, die tatsächlich dieselbe Funktion verwenden. Beispielsweise können Sie einige Funktionen haben, die eine Nachricht vorbereiten, und eine Funktion, um sie zu senden, und eine Funktion, um eine Antwort zu erhalten, aber diese beiden I/O-Funktionen werden in unterschiedlichen Zuständen verwendet.

    – qrdl

    17. August 2016 um 5:51 Uhr

  • Jeder Zustand kann als eine “sub_main_function” betrachtet werden, aufgrund der Aktionen in diesen “sub_main_functions”, kann er wieder in einen anderen Zustand wechseln, verwenden wir einen Schalter, jeder “Fallzustand:” hat mehrere Funktionen, jemand mit mir?

    – Fuev

    14. Oktober 2019 um 9:23 Uhr

Benutzeravatar von Christoph
Christoph

Ich bevorzuge die Verwendung von Funktionszeigern gegenüber gigantisch switch Anweisungen, aber im Gegensatz zur Antwort von qrdl verwende ich normalerweise keine expliziten Rückgabecodes oder Übergangstabellen.

Außerdem möchten Sie in den meisten Fällen einen Mechanismus, um zusätzliche Daten weiterzugeben. Hier ist ein Beispiel für eine Zustandsmaschine:

#include <stdio.h>

struct state;
typedef void state_fn(struct state *);

struct state
{
    state_fn * next;
    int i; // data
};

state_fn foo, bar;

void foo(struct state * state)
{
    printf("%s %i\n", __func__, ++state->i);
    state->next = bar;
}

void bar(struct state * state)
{
    printf("%s %i\n", __func__, ++state->i);
    state->next = state->i < 10 ? foo : 0;
}

int main(void)
{
    struct state state = { foo, 0 };
    while(state.next) state.next(&state);
}

  • Dein main gibt keinen Wert zurück. . . sollte es?

    – Traumlax

    20. November 2009 um 10:23 Uhr

  • @dreamlax: C99 5.1.2.2.3: Erreichen des Endes von main() implizit zurück 0

    – Christoph

    20. November 2009 um 16:01 Uhr

  • Diese Antwort hat mir sehr gut gefallen. Einfach und direkt. Gut gemacht.

    – AntonioCS

    13. Februar 2015 um 21:46 Uhr

  • Tut mir leid, ich verstehe es wirklich nicht. Was passiert in der while Bedingung in der letzten Zeile? Rufst du an foo()? Welche Standardargumente werden angenommen, wenn keine angegeben sind?

    – Multisync

    16. August 2016 um 19:41 Uhr

  • @Multisync Der Strukturinitialisierer in den vorherigen Zeilensätzen state.next (ein Funktionszeiger) auf die Adresse von foo. So state.next(&state) ist das gleiche wie foo(&state) (die erste Iteration der Schleife, sie zeigt später woanders hin). Zum Vergleich, wenn dies C++ wäre, foo() wäre Mitglied der State Klasse (State::foo()) und würde keine Parameter annehmen. Sein Körper würde verwenden this->next = bar Anstatt von state->next = bar. In C müssen Sie das Äquivalent von übergeben this Zeiger explizit, da es keine zustandsbehafteten Klassenbereiche gibt.

    – Dan Bechard

    19. Januar 2017 um 14:06 Uhr


Benutzeravatar von Michael Burr
Michael Burr

Leider sind die meisten Artikel über Zustandsautomaten für C++ oder andere Sprachen geschrieben, die Polymorphismus direkt unterstützen, da es schön ist, die Zustände in einer FSM-Implementierung als Klassen zu modellieren, die von einer abstrakten Zustandsklasse abgeleitet sind.

Es ist jedoch ziemlich einfach, Zustandsmaschinen in C zu implementieren, indem Sie entweder switch-Anweisungen verwenden, um Ereignisse an Zustände zu senden (für einfache FSMs codieren sie ziemlich direkt) oder Tabellen verwenden, um Ereignisse Zustandsübergängen zuzuordnen.

Hier gibt es ein paar einfache, aber anständige Artikel über ein grundlegendes Framework für Zustandsmaschinen in C:

Bearbeiten: Website “in Wartung”, Webarchiv-Links:

switch Anweisungsbasierte Zustandsautomaten verwenden oft eine Reihe von Makros, um die Mechanik des zu „verbergen“. switch -Anweisung (oder verwenden Sie eine Reihe von if/then/else Aussagen statt a switch) und machen so etwas wie eine “FSM-Sprache” zum Beschreiben der Zustandsmaschine in C-Quelle. Ich persönlich bevorzuge den tabellenbasierten Ansatz, aber diese haben sicherlich Vorteile, sind weit verbreitet und können insbesondere für einfachere FSMs effektiv sein.

Ein solches Framework wird von Steve Rabin in skizziert „Edelsteine ​​für die Spielprogrammierung“ Kapitel 3.0 (Entwurf einer allgemeinen robusten KI-Engine).

Ein ähnlicher Satz von Makros wird hier besprochen:

Wenn Sie auch an Implementierungen von C++-Zustandsautomaten interessiert sind, gibt es noch viel mehr zu finden. Ich werde Hinweise posten, wenn Sie interessiert sind.

Zustandsmaschinen sind nicht etwas, das von Natur aus ein Tutorial benötigt, um erklärt oder sogar verwendet zu werden. Was ich vorschlage, ist, dass Sie sich die Daten ansehen und wie sie analysiert werden müssen.

Zum Beispiel musste ich das Datenprotokoll für a analysieren Near Space Ballonflugcomputer, es speicherte Daten auf der SD-Karte in einem bestimmten Format (binär), das in eine kommagetrennte Datei analysiert werden musste. Die Verwendung einer Zustandsmaschine dafür ist am sinnvollsten, da wir je nachdem, was die nächste Information ist, ändern müssen, was wir analysieren.

Der Code wurde mit C++ geschrieben und ist verfügbar als ParseFCU. Wie Sie sehen können, erkennt es zuerst, welche Version wir parsen, und tritt von dort aus in zwei verschiedene Zustandsmaschinen ein.

Es tritt in einem bekanntermaßen guten Zustand in die Zustandsmaschine ein, an diesem Punkt beginnen wir mit dem Parsen und je nachdem, auf welche Zeichen wir stoßen, gehen wir entweder zum nächsten Zustand über oder kehren zu einem vorherigen Zustand zurück. Dadurch kann sich der Code im Wesentlichen selbst an die Art und Weise anpassen, wie die Daten gespeichert werden, und ob bestimmte Daten überhaupt existieren oder nicht.

In meinem Beispiel ist die GPS-Zeichenfolge für den Flugcomputer nicht zum Protokollieren erforderlich, sodass die Verarbeitung der GPS-Zeichenfolge übersprungen werden kann, wenn die Endbytes für diesen einzelnen Protokollschreibvorgang gefunden werden.

Zustandsmaschinen sind einfach zu schreiben, und im Allgemeinen folge ich der Regel, dass sie fließen sollte. Eingaben, die durch das System gehen, sollten mit einer gewissen Leichtigkeit von Zustand zu Zustand fließen.

Das ist alles, was Sie wissen müssen.

int state = 0;
while (state < 3)
{
    switch (state)
    {
        case 0:
            // Do State 0 Stuff
            if (should_go_to_next_state)
            {
                state++;
            }
            break;
        case 1:
            // Do State 1 Stuff    
            if (should_go_back) 
            {
                state--;
            }    
            else if (should_go_to_next_state) 
            {
                state++;
            }
            break;
        case 2:
            // Do State 2 Stuff    
            if (should_go_back_two) 
            {
                state -= 2;
            }    
            else if (should_go_to_next_state) 
            {
                state++;
            }
            break;
        default:
            break;
    }
}

  • Ich würde es für besser halten, den Zustand explizit festzulegen, aber das bin nur ich.

    – Chris Lutz

    3. September 2009 um 5:00 Uhr

  • Sie haben viel weggelassen, zum Beispiel: substates; Ereignisse und Ereignis/Zustand-Kombinationen; Zustandsübergangsdiagramme; Wachen (“Status nicht ändern, wenn”); Zustandseintritts- und Zustandsaustrittsmethoden (“beim Verlassen dieses Zustands führe die folgende Methode aus”).

    – ChrisW

    3. September 2009 um 5:05 Uhr

  • Dies ist eine zu starke Vereinfachung von Zustandsmaschinen und kein so gutes Beispiel.

    – X-Istence

    3. September 2009 um 5:08 Uhr

  • Machen Sie etwas, das sehr einfach ist, nicht zu kompliziert.

    – ChaosPandion

    3. September 2009 um 5:11 Uhr

  • Sicher, als Skelett dafür, wie eine grundlegende Zustandsmaschine aussehen könnte, könnte dies ausreichen. Aber ich denke, es ist nicht ganz “alles, was Sie wissen müssen”. Außerdem möchten Sie vielleicht Ihren Zustand unsigniert machen.

    – mrduclaw

    3. September 2009 um 6:21 Uhr

Benutzeravatar von ChrisW
ChrisW

Real-Time Object-Oriented Modeling war fantastisch (1994 veröffentlicht und jetzt für nur 81 Cent plus 3,99 $ Versand erhältlich).

  • Ich würde es für besser halten, den Zustand explizit festzulegen, aber das bin nur ich.

    – Chris Lutz

    3. September 2009 um 5:00 Uhr

  • Sie haben viel weggelassen, zum Beispiel: substates; Ereignisse und Ereignis/Zustand-Kombinationen; Zustandsübergangsdiagramme; Wachen (“Status nicht ändern, wenn”); Zustandseintritts- und Zustandsaustrittsmethoden (“beim Verlassen dieses Zustands führe die folgende Methode aus”).

    – ChrisW

    3. September 2009 um 5:05 Uhr

  • Dies ist eine zu starke Vereinfachung von Zustandsmaschinen und kein so gutes Beispiel.

    – X-Istence

    3. September 2009 um 5:08 Uhr

  • Machen Sie etwas, das sehr einfach ist, nicht zu kompliziert.

    – ChaosPandion

    3. September 2009 um 5:11 Uhr

  • Sicher, als Skelett dafür, wie eine grundlegende Zustandsmaschine aussehen könnte, könnte dies ausreichen. Aber ich denke, es ist nicht ganz “alles, was Sie wissen müssen”. Außerdem möchten Sie vielleicht Ihren Zustand unsigniert machen.

    – mrduclaw

    3. September 2009 um 6:21 Uhr

Benutzeravatar von Roman Khimov
Roman Chimov

Es gibt eine Menge Lektionen, um Zustandsmaschinen in C herzustellen, aber lassen Sie mich auch den Ragel-Zustandsmaschinen-Compiler vorschlagen:

http://www.complang.org/ragel/

Es hat eine recht einfache Art, Zustandsmaschinen zu definieren, und dann können Sie Diagramme generieren, Code in verschiedenen Stilen generieren (tabellengesteuert, gotogesteuert), diesen Code analysieren, wenn Sie möchten usw. Und es ist leistungsstark und kann in der Produktion verwendet werden Code für verschiedene Protokolle.

1418320cookie-checkTutorials zu Zustandsmaschinen [closed]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy