Boost Statechart vs. Meta State Machine

142

Anscheinend enthält boost zwei separate Bibliotheken für Zustandsautomaten: Statechart und Meta State Machine (MSM). Die Slogans geben sehr ähnliche Beschreibungen:

  • Boost.Statechart - Beliebig komplexe Finite-State-Maschinen können in leicht lesbarem und wartbarem C ++ - Code implementiert werden.
  • Meta State Machine - Eine sehr leistungsstarke Bibliothek für ausdrucksstarke UML2-Finite-State-Maschinen.

Wissen Sie, was die Hauptunterschiede sind und welche Überlegungen bei der Wahl zwischen beiden zu berücksichtigen sind?

FireAphis
quelle
4
Hehe, ein weiterer Fall von großem Interesse, aber niemand kennt die Antwort ... :)
j_random_hacker
8
: D Diese Frage ist der Höhepunkt meiner SO-Erfahrung! Antworten von beiden Entwicklern bekommen ... kann es noch besser werden?! Vielen Dank an Christophe und Andreas.
FireAphis
Ausgezeichnete Frage und Sie haben es geschafft, die Antworten der beiden konkurrierenden Entwickler zu bekommen!
Offirmo
3
Mit Statechart können Sie Funktionen in Konstruktoren und Destruktoren einfügen. Das ist ein Anti-Muster, besonders bei Destruktoren.
Lev
2
In Statechart können Exit-Aktionen in einem separaten exit () -Handler abgelegt werden, der vor der Zerstörung aufgerufen wird. Ich denke, diese Bestimmung mildert das Hauptproblem mit dem von Lev erwähnten Anti-Muster.
Tim Crews

Antworten:

116

Da es großes Interesse zu geben scheint, erlauben Sie mir bitte, meine (offensichtlich voreingenommene) Meinung zu äußern, die daher mit einem Körnchen Salz aufgenommen werden sollte:

  • MSM ist viel schneller
  • MSM erfordert keine RTTI oder etwas Virtuelles
  • MSM bietet eine umfassendere UML2-Unterstützung (z. B. interne Übergänge, UML-konforme orthogonale Regionen).
  • MSM bietet eine beschreibende Sprache (tatsächlich mehrere). Unter Verwendung des eUML-Frontends kann ein Übergang beispielsweise als Quelle + Ereignis [Wache] / Aktion == Ziel beschrieben werden
  • MSM wird Ihren Compiler unter größeren Zustandsmaschinen leiden lassen, daher benötigen Sie einen ziemlich aktuellen Compiler (g ++> = 4.x, VC> = 9).

Sie können sich eine bessere Meinung bilden, indem Sie nach Kommentaren suchen, die während der Überprüfung von MSM veröffentlicht wurden. Dieses Thema wurde auf der Entwicklerliste viel diskutiert.

Christophe Henry
quelle
2
Vielen Dank. Es ist eine Freude, die Meinung des Entwicklers selbst zu hören! Jetzt brauchen wir nur noch die Antwort von Andreas Huber :)
FireAphis
16
Minor nit-pick: Im Release-Modus ist die Verwendung von C ++ RTTI (dynamic_cast, typeid) bei Boost.Statechart streng optional.
111

Wie Christophe bereits erwähnt hat, ist einer der Hauptunterschiede zwischen den beiden Bibliotheken die Laufzeitleistung. Während MSM wahrscheinlich das Beste bietet, was Sie hier bekommen können, handelt Statechart bewusst Speicher- und Prozessorzyklen, um eine bessere Skalierbarkeit zu erreichen.

Mit Boost.Statechart können Sie das Layout (dh Zustände, Übergänge) Ihrer Zustandsmaschine auf mehrere Übersetzungseinheiten (CPP-Dateien) verteilen, wie Sie es mit MSM nicht können. Auf diese Weise können Sie die Implementierung großer FSMs wartbarer machen und eine viel schnellere Kompilierung erzielen als mit MSM.

Ob der Leistungsaufwand von Statechart im Vergleich zu MSM für Ihre Anwendung tatsächlich erheblich ist oder nicht, lässt sich häufig leicht beantworten, wenn Sie sich fragen, wie viele Ereignisse Ihre App pro Sekunde verarbeiten muss.

Unter der Annahme eines mäßig komplexen FSM, der mit Boost.Statechart implementiert wurde, sind hier einige Ballpark-Nummern:

  • Die meiste aktuelle PC-Hardware kann problemlos> 100'000 Ereignisse pro Sekunde bewältigen
  • Selbst sehr ressourcenbeschränkte Hardware kann einige hundert Ereignisse pro Sekunde verarbeiten.

In Bezug auf die CPU-Auslastung wird der Overhead von Boost.Statechart im Vergleich zu MSM mit ziemlicher Sicherheit nicht spürbar sein, wenn die Anzahl der zu verarbeitenden Ereignisse viel geringer als diese Anzahl ist. Wenn die Zahl viel höher ist, sind Sie mit MSM definitiv besser dran.

Ausführlichere Informationen zu den Kompromissen zwischen Leistung und Skalierbarkeit finden Sie hier: http://www.boost.org/doc/libs/1_45_0/libs/statechart/doc/performance.html


quelle
9
Hallo Andreas, über die Verbreitung des Layouts gab es einige Verbesserungen. Sie können jetzt Submaschinen auf verschiedenen Kernen kompilieren. Es ist nicht perfekt, aber eine spürbare Verbesserung. Siehe svn.boost.org/svn/boost/trunk/libs/msm/doc/HTML/…
Christophe Henry
11

Beim Codieren meiner eigenen PPP-Implementierung habe ich Statechart aus drei Gründen verwendet: 1) Statechart ist einfacher und hat eine klarere Dokumentation; 2) Ich mag UML wirklich nicht :)

Laut Boost-Dokumenten ist MSM mindestens 20-mal schneller, kompiliert jedoch für große FSM ziemlich langsam.

Flamme
quelle
7
Während ich zustimme, dass ein Großteil von UML die neue Kleidung des Kaisers ist, sind Zustandsdiagramme das einzige, was in UML tatsächlich Wert hat.
Jon Trauntvein
4
Auf jeden Fall, aber ich habe Zustandsdiagramme aus diskreter Mathematik gelernt, nicht aus Software-Engineering. Dies hinterlässt Spuren :)
Flamme
4

Vor einiger Zeit habe ich mit Statechart begonnen und bin zu MSM gewechselt, weil es einfacher war, in Verbindung mit asio von einem einzigen Thread aus zu verwenden. Ich habe es nicht geschafft, Statechart und seine Multithreading-Funktionen mit meiner Verwendung von asio zu verknüpfen - es war wahrscheinlich eine Art Neuling, das Statechart meinerseits nicht verstanden hat. Ich fand, dass MSM einfacher zu verwenden war, da es sich nicht mit Multithreading befasste.

Spinnenkarma
quelle
1
Die meisten Statechart-Typen befassen sich auch nicht mit Threading. In Bezug auf Multithreading sollten Sie boost :: statechart :: state_machine genau wie das MSM-Gegenstück verwenden können. boost :: statechart :: asynchronous_state_machine und zugehörige Typen sind ein streng optionaler Teil der statechart-Bibliothek.
2

Als Antwort auf Tims späten Eintritt in die Diskussion (der auch einen der sehr frühen Kommentare von Lev anspricht).

Als einer derjenigen, die sich vor langer Zeit bei der Übermittlung an Boost für die Trennung von Destruktoren im Statechart (Argument basierend auf einem realen Anwendungsfall, über die Interaktion mit der realen Welt, dh E / A) ausgesprochen haben, stimme ich zu, dass es Probleme geben kann, den Exit zu setzen Logik in Destruktoren. Es überrascht nicht, dass David Abrahams auch in Bezug auf die Ausnahmesicherheit überzeugende Argumente vorbrachte. Aus diesen Gründen verlangt Statechart nicht, dass Sie Logik in Destruktoren einfügen - aber es erlaubt Ihnen - mit den üblichen Ratschlägen.

Logik, die immer nur als Teil eines Übergangs aus einem Zustand ausgeführt werden sollte (nicht Zerstörung des gesamten Zustandsdiagrammobjekts), kann (und sollte, wenn auch eine Ressourcenbereinigung durchgeführt werden muss) in eine separate exit () -Aktion unterteilt werden.

Für einen "dünnen" Zustand ohne aktiven Zustand (Ressourcen), nur Ein- / Ausstiegsaktionen, können Sie diese Aktionen in ctor und d'tor ausführen und sicherstellen, dass der Konstruktor und der Destruktor nicht werfen. Es gibt keinen Grund für sie - es gibt keinen Zustand, an dem RAII durchgeführt werden kann - es ist nicht böse, wenn die Fehlerbehandlung an diesen Orten geeignete Ereignisse auslöst. Möglicherweise müssen Sie noch überlegen, ob Exit-Aktionen, die den externen Status ändern, bei Zerstörung der Zustandsmaschine ausgeführt werden sollen ... und sie in die Exit-Aktion setzen, wenn Sie in diesem Fall nicht möchten, dass sie ausgeführt werden ...

Statechart modelliert die Aktivierung als Instanziierung eines Objekts. Wenn Ihr Konstruktor also echte Arbeit / Aktivierung / Instanziierung zu erledigen hat und wenn dies fehlschlagen kann, sodass der Status nicht eingegeben werden kann, unterstützt Statechart dies, indem Sie eine Ausnahme einem zuordnen können Veranstaltung. Dies wird so gehandhabt, dass die Statushierarchie nach einem äußeren Zustand sucht, der das Ausnahmeereignis behandelt, analog zu der Art und Weise, wie der Stapel für ein auf einem Aufrufstapel basierendes Aufrufmodell abgewickelt worden wäre.

Dies ist alles gut dokumentiert - ich schlage vor, Sie lesen die Dokumente und versuchen es. Ich schlage vor, dass Sie Destruktoren verwenden, um "Softwareressourcen" zu bereinigen und Aktionen zu beenden, um "reale Exit-Aktionen" auszuführen.

Es ist anzumerken, dass die Weitergabe von Ausnahmen in allen ereignisgesteuerten Umgebungen ein Problem darstellt, nicht nur in Zustandsdiagrammen. Es ist am besten, Fehler zu begründen und in Ihr Statechart-Design aufzunehmen, und wenn und nur wenn Sie sie nicht auf andere Weise behandeln können, greifen Sie auf die Ausnahmezuordnung zurück. Zumindest funktioniert das bei mir - ymmmv ....

da77a
quelle
Vielen Dank, ich sehe, dass alle meine Bedenken im Teil "Ausnahmebehandlung" des Boost :: statechart-Tutorials ausreichend behandelt werden. In diesem Fall denke ich, dass Levs (irreführender) Kommentar einfach durch Verweisen auf den Abschnitt "Zweistufiger Ausgang" dieses Tutorials angesprochen werden kann. Ich würde in Betracht ziehen, meine Antwort zu löschen, außer dass Ihre eigene Antwort diesem Thema wertvolle Informationen hinzufügt.
Tim Crews