Hallo,
ich möchte gerne eine zwei stufige State Machine zu programmieren. Nur
ist mir noch nicht ganz klar, wie ich es anstelle. Das ganze soll in
einer klassischen Zeitscheiben-Scheduler laufen. Die State Machine merkt
sich dabei die zuletzt ausgeführte Operation.
Das ganze ist zwei Stufig.
1. Stufe : 4 Zusände
2. Stufe : Je ca. 10 Zusände
Bisher habe ich die States in einem eigenem enum angelegt und gemerkt.
Aber irgendwie wird das zu unübersichtlich / umständlich.
1
enum{
2
STATE_1,
3
STATE_2,
4
STATE_3
5
}state
6
7
enum{
8
STATE1_1,
9
STATE1_2,
10
STATE1_3,
11
...
12
}state1
13
14
enum{
15
STATE2_1,
16
STATE2_2,
17
STATE2_3,
18
...
19
}state2
Hier mal exemplarisch dargestellt.
Wie kann man das besser lösen?
Christian R. schrieb:> Das ganze ist zwei Stufig.> 1. Stufe : 4 Zusände> 2. Stufe : Je ca. 10 Zusände> Wie kann man das besser lösen?
Besser Namen wählen ;-) Scherz beiseite. Wenn Du wirklich 40
verschiedene Zustände hast, und die Unterzustände für jeden der 4
Zustände unterschiedlich sind, dann würde ich eine enum für den
Haupzustand wählen und 4 enums für die Unterzustände. Einfach wird es
nicht werden.
Evtl. versuchst Du aber auch mehr als einen Automaten in einem
abzubilden?
mfg Torsten
Wilhelm M. schrieb:> Die Antwort ist Kapselung.
Kann man in C wunderbar machen.
> Und das erreichst Du besser mit C++
GLeich in der 2. Antwort mit C++-Getrolle offtopic geworden - reife
Leistung.
Das primäre Problem scheint mir zunächst nicht-technischer Art zu sein.
Bei Problemen, gleich welcher Art, sollte man aufmerken, wenn man Wörter
wie "irgendwie" zur Beschreibung benutzt. Es hilft dann weiter, wenn man
sie durch präzise Adjektive ersetzt. Man kann sich Wie-fragen stellen, -
etwa: Wie, wann, wodurch etcpp. -, um das zu erreichen.
Das Ergebnis enthält meist schon Hinweise auf die Antwort.
Wenn die jeweils 10 Unterzustände irgendwie ähnlich sind, kannst Du sie
"mergen", also eine Obermenge bilden (sind dann vielleicht 15, wovon
nicht alle in jedem Hauptstate vorkommen).
Wenn die jeweils 10 Unterzustände verschieden sind, und innerhalb eines
Hauptzustandes beliebig angewählt werden, dann gilt:
Torsten R. schrieb:> dann würde ich eine enum für den Haupzustand wählen> und 4 enums für die Unterzustände. Einfach wird es nicht werden.
Wenn die jeweils 10 Unterzustände ausschließlich sequentielle
abgearbeitet werden, dann gäbe es die Möglichkeit mit reinen Zahlen,
also:
1
/* all 10 state defined explicit and unconditional increment */
2
{
3
switch(sub_state)
4
{
5
case0:/* do whatever to do in first state */
6
break;
7
case1:/* do whatever to do in second state */
8
break;
9
...
10
case9:/* ... */
11
break;
12
default:/* flag error */
13
flag_error(sub_state);
14
sub_state=0;
15
break;
16
}
17
if(sub_state<9){sub_state++;}
18
else{sub_state=0;}
19
}
20
21
/* set of states, 10 Maximum */
22
{
23
switch(sub_state)
24
{
25
case0:/* do whatever to do in first state */
26
sub_state++;/* unconditional next state */
27
break;
28
case1:/* do whatever to do in second state */
29
if(...){sub_state++;}/* with condition */
30
break;
31
...
32
case9:/* ... */
33
sub_state++;
34
break;
35
default:/* skip this one or set to 0 */
36
if(sub_state<9){sub_state++;}
37
else{sub_state=0;}
38
break;
39
}
40
}
Das ist aber nicht wirklich schön!
Macht aber manchmal Sinn, wenn man nur irgendwie 10 Dinge nacheinander
machen möchte...
Nop schrieb:> Wilhelm M. schrieb:>> Die Antwort ist Kapselung.>> Kann man in C wunderbar machen.>>> Und das erreichst Du besser mit C++>> GLeich in der 2. Antwort mit C++-Getrolle offtopic geworden - reife> Leistung.
Das war ja wieder klar:
der TO stellt eine Frage wie: ich möchte mit der Nagelfeile einen Nagel
in die Wand schlagen, und Du antwortest ihm, dass das gut geht und er
die Feile nur am richtigen Ende anfassen muss.
Ich aber antworte ihm: nimm lieber einen Hammer.
Wilhelm M. schrieb:> Das war ja wieder klar:> der TO stellt eine Frage wie: ich möchte mit der Nagelfeile einen Nagel> in die Wand schlagen, und Du antwortest ihm, dass das gut geht und er> die Feile nur am richtigen Ende anfassen muss.> Ich aber antworte ihm: nimm lieber einen Hammer.
Ich bin ja auch ein großer Fan von C++. Aber: Der TO hat explizit C in
der Überschrift erwähnt und evtl. hat er auch einfach seine Gründe,
warum er C verwendet.
P.S: Nicht alles was hinkt ist ein Vergleich!
Wilhelm M. schrieb:> Ich aber antworte ihm: nimm lieber einen Hammer.
Nein, du behauptest es muss ein 600g Hammer sein. Dabei gibt es Nägel
die mit einem 400 oder 300g Hammer viel besser einzuschlagen sind.
Wer eine State machine nicht in C hinkriegt, der kriegt sie mit C++
schon gar nicht hin.
Du bist derjenige der meint jeder müsste genau dein präferiertes
Werkzeug benutzen, dabei ist das Problem des TO viel tiefgreifender.
Die Organsisation seiner States dürfte das kleinste Problem sein wenn
man 2 verschachtelte State-machines mit 4 x 10 States meint bauen zu
müssen.
Torsten R. schrieb:> Wilhelm M. schrieb:>>> Das war ja wieder klar:>> der TO stellt eine Frage wie: ich möchte mit der Nagelfeile einen Nagel>> in die Wand schlagen, und Du antwortest ihm, dass das gut geht und er>> die Feile nur am richtigen Ende anfassen muss.>> Ich aber antworte ihm: nimm lieber einen Hammer.>> Ich bin ja auch ein großer Fan von C++. Aber: Der TO hat explizit C in> der Überschrift erwähnt und evtl. hat er auch einfach seine Gründe,> warum er C verwendet.
Einer der Gründe könnte sein, dass er es aus Unwissenheit nicht in
Betracht gezogen hat, oder er ggf. nicht weiß, wie er Sprachen wie C,
C++, Java, etc. mischen kann, ...
Der Andere schrieb:> Wilhelm M. schrieb:>> Ich aber antworte ihm: nimm lieber einen Hammer.>> Nein, du behauptest es muss ein 600g Hammer sein. Dabei gibt es Nägel> die mit einem 400 oder 300g Hammer viel besser einzuschlagen sind.> Wer eine State machine nicht in C hinkriegt, der kriegt sie mit C++> schon gar nicht hin.
Das wiederum glaube ich nicht: da viele Leute es auf einem höheren
Abstraktionsniveau nachweislich besser schaffen als low-level, liegt
auch hier die Vermutung nahe. C++ war auch mehr pars pro toto, gemeint
war mehr OOD.
> Du bist derjenige der meint jeder müsste genau dein präferiertes> Werkzeug benutzen, dabei ist das Problem des TO viel tiefgreifender.
Gar nicht. Ich schrieb, er können mal darüber nachdenken ;-)
Wilhelm M. schrieb:> C++ war auch mehr pars pro toto, gemeint war mehr OOD.
Schon wieder Bullshit. Man kann Statemachines problemlos in C machen.
OOD ist dafür schlichtweg überflüssiges Spielzeug, genau wie C++.
Christian R. schrieb:> Hier mal exemplarisch dargestellt.> Wie kann man das besser lösen?
Indem man sich erstmal Gedanken um ein Design macht. 4x10 Zustände, die
"irgendwie" gekoppelt sind, werden immer zu häßlichem Chaos führen.
Da Du zur Problemstellung an sich nichts sagst, werden konkrete Hinweise
schwierig. Eine zweistufige Statemachine würde man aber normalerweise so
machen, daß man eine high-level-statemachine hat, mit 4 Zuständen. Diese
ruft dann in jedem Zustand genau einen der low-level-Automaten auf (die
mit 10 Zuständen).
Entscheidend ist, daß die low-level-Automaten voneinander nichts wissen
und auch keine Ergebnisse teilen.
Wenn das nicht möglich ist: Problem neu analysieren.
Wenn der TS mit symbolische Namen arbeiten will, die auch ("öffentlich")
sichtbar sind (also potentiell kollidieren), dann bietet C++ mit
Namespaces schon einen Vorteil.
Ansonsten sind 40 Zustände aber auch noch nicht soo kompliziert. Ein
zentrales gut dokumentiertes Modul für die Funktionseinsprünge in der
Art von Achims Vorschlag ist ok, denke ich.
Das ist aber nur die halbe Miete. Interessant wird die Beschreibung der
Zustandsübergänge (wenn es denn tatsächlich eine State Machine ist und
nicht nur Save Points). Damit man sich (auch noch nach ein paar Monaten)
zurecht findet, gibt es imho keine Alternative zu einer grafischen
Dokumentation (oder zumindest eine Tabelle).
Wilhelm M. schrieb:> da viele Leute es auf einem höheren> Abstraktionsniveau nachweislich besser schaffen als low-level, liegt> auch hier die Vermutung nahe
Ist das Deine Erfahrung oder kannst Du das irgendwie belegen?
Dass die allermeisten Statemachines von 4*10 auch verkleinert werden
können (ggf. zum Preis der Unleserlichkeit), geschenkt. Aber warum das
in OOP besser geht als mit Papier und Bleistift, UML oder C, ist wohl
nur dem klar, der OOP besser kann als eines der anderen.
Christian R. schrieb:> Aber irgendwie wird das zu unübersichtlich / umständlich.
Lager die einzelnen Automaten in einzelne Module aus. Dann bleibt es
übersichtlich.
Achim S. schrieb:> Wilhelm M. schrieb:>> da viele Leute es auf einem höheren>> Abstraktionsniveau nachweislich besser schaffen als low-level, liegt>> auch hier die Vermutung nahe>> Ist das Deine Erfahrung oder kannst Du das irgendwie belegen?
Ich kann Dir natürlich keine Studie darüber liefern, die das belegt.
Allerdings habe ich die Erfahrung gemacht, dass ein deklarativer Ansatz
oft anderen Personen leichter zu vermitteln ist als ein prozeduraler. In
diesem Beispiel heißt das, dass man die Zustandsübergänge abstrakt (ggf.
durch eine DESL) beschreibtohne sie im Code zu "verstecken".
Das ist vergleichbar mit deklarativen UI Beschreibungen. Das können auch
Personen, die wenig von der Technik wissen.
Wilhelm M. schrieb:> diesem Beispiel heißt das, dass man die Zustandsübergänge abstrakt (ggf.> durch eine DESL) beschreibtohne sie im Code zu "verstecken".
In diesem Beispiel ist das Problem doch eher, daß es kein Design zu
geben scheint, bzw. daß das Design verworren ist. Das Runtercoden danach
ist reine Fleißarbeit, das kann auch ein dressierter Affe.
Nop schrieb:> Wilhelm M. schrieb:>>> diesem Beispiel heißt das, dass man die Zustandsübergänge abstrakt (ggf.>> durch eine DESL) beschreibtohne sie im Code zu "verstecken".>> In diesem Beispiel ist das Problem doch eher, daß es kein Design zu> geben scheint, bzw. daß das Design verworren ist. Das Runtercoden danach> ist reine Fleißarbeit, das kann auch ein dressierter Affe.
Sehe ich auch so. Wenn er kein Diagramm mit Papier und Bleistift malen
kann, kriegt er es auch nicht in irgendeinen Automaten.
Wilhelm M. schrieb:> Sehe ich auch so. Wenn er kein Diagramm mit Papier und Bleistift malen> kann, kriegt er es auch nicht in irgendeinen Automaten.
Jepp, und das setzt sich danach noch fort, weil man ohne so ein Diagramm
ja auch keine Testfälle entwerfen kann. Und beim reinen Ausprobieren
werden mit Sicherheit einige Übergänge ausgelassen, besonders die für
Fehlerbehandlung.
Wilhelm M. schrieb:> Ich aber antworte ihm: nimm lieber einen Hammer.
Das glaubst aber auch nur du, vielleicht nichtmal du...
De facto bringen die gegenüber C erweiterten Ausdrucksmöglichkeiten von
C++ im konkreten Fall natürlich exakt NULL Vorteile.
Christian R. schrieb:> Hier mal exemplarisch dargestellt.> Wie kann man das besser lösen?
[ ] in einem Forum Fragen, das vor Freitagstrollen und Besserwissern nur
so strotzt
[x] Hinsetzen und runterschreiben. Dann schauen ob's so schlimm war und
DIR gefällt. Oft merkt man auch erst mitten drin, das was am Design
falsch ist. Natürlich hätte man vorher in einem Forum fragen können,
aber die Struktur des Programms und die Übergänge hinzutippen dauert
vielleicht eine Stunde. Das Gesülze im Forum zu lesen dauert einen Tag
und führt zu nichts.
Und jetzt mein Gesülze, wie ich es gerne mache:
- Welche Zustandsübergänge gibt es?
- Durch welche Signale werden diese ausgelöst?
- Ergibt sich daraus eine vernünftige Schnittstelle?
- Zustandsübergangslogik trennen von den Aktionen in einem Zustand
(Idealvorstellung der klassischen Digitaltechnik)
- 40 Zustände? So wenige? ;-) Keine Angst, hab Mut
Achim S. schrieb:> Dass die allermeisten Statemachines von 4*10 auch> verkleinert werden können (ggf. zum Preis der> Unleserlichkeit), geschenkt.
Nach meinem Verständnis ging es nicht um Minimierung,
sondern um Allgemeinverständlichkeit.
Das steht, wie Du ja selbst auch sagst, im direkten
Gegensatz zueinander.
> Aber warum das in OOP besser geht als mit Papier> und Bleistift, UML oder C, ist wohl nur dem klar,> der OOP besser kann als eines der anderen.
Naja, die Wahrheit ist, dass das "O" in OOP für
"Automaten" steht. Das wissen die OOP-Leute (i.d.R.)
nur nicht.
(Wilhelm bildet die Ausnahmen von dieser Regel.)
Die "Felder", "Membervariablen" etc. bilden die Flipflop-
Batterien der Automaten. Die Routinen ("Methoden") bilden
die Kombinatorik; das Interface entspricht den
Anschlusspins.
Die Schöpfer der OOP sind primär dafür zu hassen, dass
sie unbedingt ein "völlig neues" Pseudo-Universum schaffen
mussten, statt an die seit Ewigkeiten bekannten Begriffe
der Automatentheorie anzuknüpfen.
Mit diesem Vorwissen ist es naheliegend, einen Zusammenhang
zwischen der OOP und den "state machines" zu sehen: "state
machines" sind auch nur (endliche) Automaten.
Zur Laufzeit aufgebaute Hierarchien von "Instanzen" sind
lediglich Automatennetze -- aber das klingt ja nicht so
unverständlich und ist daher uncool...
Lösung in C.
int zustand = 0; // start
int Automat [4][10], = { {3,1,4,6,0,0,0,0,0,0},
{13,12,12,18,16,12,19,15,11,10},
{3...},
{...}
};
zustand = zustand[Automat[zustand][uebergang];
/////////////////
2 dim Arrays werden im
Speicher hintereinander abgelegt.