How do you handle state-independent events efficiently in MSM?
I have a state machine that has a large number of event types but only a few different states. Some of the events can be received regardless of the state and the same action is taken regardless of which state the machine is in, so the event is really unrelated to the state. I there an efficient way of handling the events that are state independent rather than defining a transition from every possible state for each state independent event? A number of the events do transition the state machine and depend on the current state, so a transition is necessary. But if no state change is required for the event and the current state is not important, I'm not sure how to define event handling without defining a transition from all possible states. This winds up creating a much larger number of transitions than I really need, and a much longer compile time than I would like. I am looking for some way to handle these states that would still give me good run time speed, put not pay the penalty that defining a large number of transitions would impose. Thanks! Peter Gissel
I have a state machine that has a large number of event types but only a few different states. Some of the events can be received regardless of the
state and the same action is taken regardless of which state the machine is in, so the event is really unrelated to the state. I there an efficient way
of handling the events that are state independent rather than defining a transition from every possible state for each state independent event?
Clearly, this would be pretty ugly.
A number of the events do transition the state machine and depend on the current state, so a transition is necessary. But if no state change is
required for the event and the current state is not important, I'm not sure how to define event handling without defining a transition from all
possible states. This winds up creating a much larger number of transitions than I really need, and a much longer compile time than I would like. I am
looking for some way to handle these states that would still give me good run time speed, put not pay the penalty that defining a large number of
transitions would impose.
There are 2 ways. The most evident would be to define internal transitions in your fsm. This means that they are taken (or not, depending on your guards and transition conflicts) whatever state currently is active. For example, you could add to the fsm: struct internal_transition_table : mpl::vector< Internal < internal_event , internal_fct,internal_guard >
{};
This will cost you 1 transition / event, so in your case, much less compile-time. Except, that I just tried before I send this and it works on submachines but not on the outer state machine :( I will check this asap, but in the meantime, we will move to plan B. Define a second region in your fsm, with only one dummy state, then add for every event you want to process independently of your "regular" states a transition in the fsm from this dummy state to itself (or give this state an internal transition table). As every region gets a chance to process any event, you will get the same effect and the reduced compilation time. In the meantime I'll check why the internal table does not behave like advertised.
Thanks!
Peter Gissel
HTH, Christophe
we will move to plan B. Define a second region in your fsm, with only one dummy state, then add for every event you want to process independently of your "regular" states a transition in the fsm from this dummy state to itself (or give this state an internal transition table).
As every region gets a chance to process any event, you will get the same effect and the reduced compilation time.
Thanks, this is exactly what I was looking for! I implemented this and it works perfectly, and it cut down my transition table significantly! The next question applies to another smaller subset of events I need to deal with. These can also happen regardless of what state the machine is in, but transition the machine to a one my "regular" states. I can use a similar approach with these, but obviously I need an additional method to put the machine back to the dummy state in addition to the "regular" state the incoming event transitions the machine to. How would I implement this, or something that accomplishes something similar? Thanks! Pete
we will move to plan B. Define a second region in your fsm, with only one dummy state, then add for every event you want to process independently of your "regular" states a transition in the fsm from this dummy state to itself (or give this state an internal transition table).
As every region gets a chance to process any event, you will get the same effect and the reduced compilation time.
Thanks, this is exactly what I was looking for! I implemented this and it works perfectly, and it cut down my transition table significantly!
Good. It turns out, I simply oversaw the case of internal transitions for the main fsm. It's not an implementation bug, but a design one, which is much worse because if implies bigger changes :(
The next question applies to another smaller subset of events I need to deal with. These can also happen regardless of what state the machine is
in, but transition the machine to a one my "regular" states. I can use a similar approach with these, but obviously I need an additional method to
put the machine back to the dummy state in addition to the "regular" state the incoming event transitions the machine to. How would I implement
this, or something that accomplishes something similar?
I'm not sure I understand this, could you elaborate? If one region transitions from one state to another, it has no influence on other regions. To the other part, there is no simple way to say "transition from any state to State X". The only way is to move all states except the target to a submachine, then transition from the submachine to state X. If you transition back and want to remember where you were, you use a history. Of course, this is not perfect because you cannot make a state belong to several submachines. This is something I need to put on my list, it would be nice to have a transition from whatever to state X. HTH, Christophe
we will move to plan B. Define a second region in your fsm, with only one dummy state, then add for every event you want to process
independently of your "regular" states a transition in the fsm from this dummy state to itself (or give this state an internal transition table).
As every region gets a chance to process any event, you will get the same effect and the reduced compilation time.
Thanks, this is exactly what I was looking for! I implemented this and it works perfectly, and it cut down my transition table significantly!
The next question applies to another smaller subset of events I need to deal with. These can also happen regardless of what state the machine is
in, but transition the machine to a one my "regular" states. I can use a similar approach with these, but obviously I need an additional method to
put the machine back to the dummy state in addition to the "regular" state the incoming event transitions the machine to. How would I implement
this, or something that accomplishes something similar?
Thanks!
Pete
Hi, it took a little long but I managed to make plan A work. If you provide an internal transition table (internal_transition_table) in your fsm definition, you can avoid having to define a second region with a single state. Instead you get a transition looking like this: struct internal_transition_table : boost::mpl::vector< Internal < event , action , guard >
{};
In this case, action and guard are functors but it works with other rows too. You will need the latest trunk version. HTH, Christophe
Hi,
it took a little long but I managed to make plan A work. If you provide an internal transition table (internal_transition_table) in your fsm definition, you can avoid >having to define a second region with a single state. Instead you get a transition looking like this:
struct internal_transition_table : boost::mpl::vector<
Internal < event , action , guard >
{};
In this case, action and guard are functors but it works with other rows too.
You will need the latest trunk version.
Thanks, excellent work, I'll give this a try. What are the trade-offs/advantages between this approach and plan b? Are there any performance differences, or mostly just style methodology?
it took a little long but I managed to make plan A work. If you provide an internal transition table (internal_transition_table) in your fsm definition,
you can avoid having to define a second region with a single state. Instead you get a transition looking like this:
struct internal_transition_table : boost::mpl::vector<
Internal < event , action , guard >
{};
In this case, action and guard are functors but it works with other rows too.
You will need the latest trunk version.
Thanks, excellent work, I'll give this a try. What are the trade-offs/advantages between this approach and plan b? Are there any performance
differences, or mostly just style methodology?
Mostly style, though the performance is likely to be a little better. The reason is that if you have 2 regions, all events are tried in both regions, so twice the dispatch speed of one region. If you use an internal table, only those events not processed by the one region will be tried by the internal table (MSM does check at compile-time if it is worth trying an event for the internal table. If the event is not found there, it is not tried and processing stops here). Granted, it is not a huge speed gain, but any gain is happily taken ;-) For the style, it allows you to provide 2 kinds of internal transitions for submachines, either as rows in the main machine, or as internal table in the submachine, so you get more flexibility. Regards, Christophe
participants (2)
-
Christophe Henry
-
Peter Gissel