|
Boost : |
Subject: Re: [boost] [msm] guard behavior if guard guards the transition MSM threats event as handled is that correct ?
From: Richard Szabo (sz.richard_at_[hidden])
Date: 2011-11-24 20:54:37
Hi Christophe
> Sure. I see other ways out of your problem. I think they are elegant and
> conform to the spirit of state machines:
> - exit points, as previously said. Just write another region as last, which
> will process your event and send it out to the outer. This has the
> disadvantage to force you to check is the event has been processed or not.
> - internal transitions in the submachine itself. IIUC, SubRunning is meant
> to be a submachine, right? Then we only need to add this to its definition:
>
> struct internal_transition_table : mpl::vector<
> Internal < event3 , Action , Guard >
> > {};
>
>
> (supposing you need a guard, this is optional).
> What does this mean? We added to your submachine (or substate) an internal
> transition table. By convention, MSM decides this is less "inner" than a
> standard transition table, so the transition table is tried first. If no
> transition from the transition table processes the event (or if the event is
> rejected by guards), then the internal table is tried.
> This can be easily used to replace your use of no_transition, it is more
> elegant, Standard-conforming and you have extra capabilities (like having
> different handlers, conflicting ones solved by guards, etc). I find this
> quite fun :)
>
Great Great Great .... you are always 1 step a head of me ....
Yes this sunds a nice solution and even I can hide the internal
transition table in ta sub state machine running base state all states
creating sub states are just can use this base state ....
This is cool I hope internal_transition_table allows to use baseEvents
as well like outer ones ...
> The whole internal transitions have been rewritten in 1.48 to allow this to
> work for all machines so you will need it or trunk (sadly this also means
> that while I tested as well as I could, I cannot exclude the possibility of
> a bug).
Don't worry I will come back to you if it is buggy ... I think with
our virtual test system we will find problems quick if there any ...
Thanks for the support
Cheers
Richie
On 24 November 2011 22:21, Christophe Henry
<christophe.j.henry_at_[hidden]> wrote:
>> Here is the execution output of the example attached :
>>
>> MS1 Entering State: Idle by: event1
>> MS1 Leaving State: Idle by: event1
>> MS1 Entering State: SubRunning by: event1
>> FwdGuard: returns:1, event: event2
>> Processing BaseEvent Instance(event2)
>> Setting guard false
>> FwdGuard: returns:0, event: event3
>> MS1 DEFERED: event3
>> FwdGuard: returns:0, event: event4
>> FwdGuard: returns:0, event: event3
>> MS1 DEFERED: event3
>> FwdGuard: returns:0, event: event5
>> MS1 Leaving State: SubRunning by: event5
>> MS1 Entering State: AfterSub by: event5
>> MS1 no_transition event (event3)
>>
>> It seems that the bug not fixed ...
>
> Sorry, I should have been more explicit (and avid sheating to save a guard).
> You need to invert your 2 transitions to get the desired effect (processing
> is done from the bottom of the table):
>
> Row < SubRunning , baseEvent , none , ProcessBaseEvent ,
> FwdGuard >,
> Row < SubRunning , event3 , none , LogDefer , none >
>
> Now, deferring has a higher priority, which gives the following desired
> output:
>
> MS1 Entering State: Idle by: event1
> MS1 Leaving State: Idle by: event1
> MS1 Entering State: SubRunning by: event1
> FwdGuard: returns:1, event: event2
> Processing BaseEvent Instance(event2)
> Setting guard false
> MS1 DEFERED: event3 // ok, defer event3
> FwdGuard: returns:0, event: event4 //event4 is not deferred
> MS1 DEFERED: event3 // event4 processed, can we process event3? Nope, defer
> again
> FwdGuard: returns:0, event: event5
> MS1 Leaving State: SubRunning by: event5
> MS1 Entering State: AfterSub by: event5 // we changed state, can we process
> event3?
> MS1 no_transition event (event3) // yes but we have no transition, call
> handler
>
>
>> but this is my least worries (
>> partly my fault You have asked me to test it for you .... but I did
>> not sorry about that).
>
>> My bigger problem is the interpretation of no_transition you saying
>> that it is an error situation... Well I have in my code a lot of
>> situation when there are signals which are not interested to my state
>> machine but they are dispatched to me anyhow our modules are used by
>> different places for different purposes and there are signals which
>> are useful in one case but not needed for my purpose I just simply
>> ignore them these are ending up in no_transition so there I just write
>> a log entry that signal is not handled so for me it is not an error at
>> all it is the intended behavior.
>
> State machines have a long history in the hardware world. And there it is
> tradition that if no transition processes an event, it is an error. Purists
> spend a lot of time handling every event in every state and even have state
> tables to check this.
> This means that to be completely correct, we should write an internal
> transition in every state for every event to document we choose to ignore
> these events (I try to do it regularly and it does help me from time to
> time).
> The UML Standard kept all this. When a transition could handle the event but
> rejects it, the event is processed. For once the Standard is about clear...
> ;-)
> But there are solutions to your problem in MSM's toolbox.
>
>> Now back to the My blocking problem .....
>>
>> We use at the moment about 36 MSM state machines
>
> :)
>
>> out of this 26 are
>> performing specific well defined configuration task these 26
>> state-machine are nested to each in to each other to perform
>> complicated behaviors sometimes there are nesting goes done to 5 level
>> deep. We have, I call them main state machines which are connect
>> these small task to each other to build complex behavior. We have more
>> than 500 different row entries spitted in to these state machines.
>> At the beginning we try to use MSM way of state machine nesting and
>> soon we figured out that there is no compiler in the word which can
>> compile/link this code.
>
> Admittedly. We'll have to be patient.
>
>> Than I have decided to make smaller compile unit and make each state
>> machine as a separate compile unit and let communicate them over a
>> simple interface.
>> Yes this slows done the dispatching because we have to re-dispatch
>> each event in run-time as many times as many nesting level we have.
>> But this tread of is acceptable. And yes this way state machines are
>> holding references to outer state machines if it is running as a
>> nested state machine and states which are nested state machines are
>> holding references to inner state machine instances. Every state
>> machine uses the same interface to communicate and we hide the
>> construction of the state machines with factories. So this way the
>> outer does not exposed to the inner the inner does not exposed to the
>> outer leads us to a compile-able code :).
>
> I personally use callbacks with boost::function or signals to avoid cycles
> but yes, it is still a logical cycle.
>
>> In case the state machine is in a stare where the sate is actually a
>> holder of an inner state machine there is a Row with a baseEvent which
>> this case re-dispatches the event to the inner one. Now if the inner
>> one does not handles the event it shall send it back to the outer one.
>> My assumption was that I can use the no_transition for this purpose
>> but the implementation turns out different :(. For me name
>> no_transition suggests that if no transition triggered. This function
>> will be called and if the guard rejects the transition than this means
>> to me that the transition is not triggered.
>> Anyhow we could argue on it but in the end it does not help with my
>> problem ....
>
> Sure. I see other ways out of your problem. I think they are elegant and
> conform to the spirit of state machines:
> - exit points, as previously said. Just write another region as last, which
> will process your event and send it out to the outer. This has the
> disadvantage to force you to check is the event has been processed or not.
> - internal transitions in the submachine itself. IIUC, SubRunning is meant
> to be a submachine, right? Then we only need to add this to its definition:
>
> struct internal_transition_table : mpl::vector<
> Internal < event3 , Action , Guard >
> > {};
>
>
> (supposing you need a guard, this is optional).
> What does this mean? We added to your submachine (or substate) an internal
> transition table. By convention, MSM decides this is less "inner" than a
> standard transition table, so the transition table is tried first. If no
> transition from the transition table processes the event (or if the event is
> rejected by guards), then the internal table is tried.
> This can be easily used to replace your use of no_transition, it is more
> elegant, Standard-conforming and you have extra capabilities (like having
> different handlers, conflicting ones solved by guards, etc). I find this
> quite fun :)
>
> The whole internal transitions have been rewritten in 1.48 to allow this to
> work for all machines so you will need it or trunk (sadly this also means
> that while I tested as well as I could, I cannot exclude the possibility of
> a bug).
>
> HTH,
> Christophe
>
>
>
> _______________________________________________
> Unsubscribe & other changes:
> http://lists.boost.org/mailman/listinfo.cgi/boost
>
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk