Boost logo

Boost Users :

Subject: Re: [Boost-users] [MSM] a timer/timeout for the whole state machine (including submachines)
From: Albert Gil Moreno (albert.gil_at_[hidden])
Date: 2012-04-12 04:26:21


Thanks a lot for your time and suggestions Christophe!

> Let me see if I got it right. You want a timer to count from x to 0, and when timer == 0, generate a timeout event, correct?
> Then you want the possibility to reset the timer.
> IIUC, you implemented your timer as a second region with a single Timer state. This looks so far ok to me because the region can process events to the state machine (for other regions).
> Of course, the more complicated your timer gets, the harder it becomes.

You are totally right!
:-)

>> - A Timer inside all my (sub)state machines?
> Sounds like a lot of work ;-)

agree!
;-)

>> - An independent state machine only for the Timer and (not so ugly)
>> pointers from/to it in all my (sub) state machines?
> This looks like a perfect use case for a submachine. Define it once as an independent state machine and reuse it in any state machine needing a timer.

Yes!
In my first approach i use only an independent and reusable "state"
and not a complete "state machine", but my idea is what you say:
independent and reusable! ;-))

> So far so good, but you are stuck with how to inform client state machines of your timer that there is a timeout, right?

mmm... not exactly...

In fact, the timeout is working fine.
It is sent from the timer state/region and processed fine in the
"main" machine/region, and in their submachines.

Is the reset event (only when generated in a submachine of the main
machine/region) which is really failing.

The reset is always generated when there is "activity" in the main
machine/region, where I (could) have submachines.
If there is "activity" in a submachine, the reset event is generated
in the submachine (but not up-fwd) and then is not processed by the
timer region of the upper state machine...

So, until now, the *reset in a submachine* is my real problem, not the
timeout (which work great!).

>> - More work on the pseudo exit?
> - use the UML way. The timer is a state machine, with a pseudo exit when a timeout is detected. This is an encapsulated submodule used by any fsm. Like a well-behaved submodule, it advertises that timeout events are going to be fired through the pseudo exit. How it is done inside is not the outer fsm's business.

Ok, iiuc, this is a better way to define that a timeout is going to be
sent outside the state machine.
And, although now the timeout is not a problem for me, i understand
that pseudo-exit is the standard way to say "I'm a (full) state
machine but I'm sending events out of me". is this correct? (i should
read something about uml right now! ;-)

Then I should probably use them (the pseudo exists) also for the
resets generated in my submachines...
I have to read more on pseudo exits...

> This has several advantages:
> - no ugly pointer
> - UML-conform
> - perfectly reusable and encapsulated timer for different uses. Often, fsm's need a timer but differ in how they handle timeouts. Leave it to them. The documentation states the timeout is sent through a pseudo exit. Or several pseudo exit states.
> - the timer is a state machine in its own right, you can write a wonderful unit test for it alone.

That's exactly what i'was looking for!
:-))

But here I'm still missing my real problem: how to (say in the
documentation and to) implement the fact that the timer can/should
receive "reset" events from any (sub) state in the orthogonal
region(s).
May be pseudo-entries...?

>> For this reason I could think that a (sub) state machine could handle
>> some "no_transitions" for some events (some cached cases), but it can
>> also auto-upper-fwd them to the parent state machine...
> I understand but it's not the way the Standard is thought (well, at least I think). You're supposed to process an event on the outer, which then uses priority rules to know what's done (deeper first, completion events, deferred events, conflicts, etc.).

I see, but iiuc the standard way is fine for me!

I mean, iiuc, the key difference here between the standard and the msm
is that in the standard all events are always processed by the outest
sm (and then it uses the prioty rules), and in msm we can process
events in the "submachine scope" (in fact, until now, if we hate ugly
pointers, then we are forced to process events only in that submachine
scope, right? ;-).

Then, iiuc, if msm removes the possibility of processing events
directly into submachines but the event processing is always done
starting from the outer state machine, then everything should work
(and be more standard-conform)?
Am I missing something here?

I mean, the upper-fwd is probably a kind of bad idea needed (or
useful) only because msm allows (now it "forces") event processing
directly in submachine scopes, if not, every thing should just work?

If I'm right, then, I'm wondering if the processing of events directly
in submachines is useful in some cases...?
I mean, I see that access to the submachine can be useful if someone
has some kind of "global" data members in it (shared by all the
states) and want to access them...

But the fact of event processing, is really useful in any case?
Forcing the event processing to start always to the outest state
machine should not remove any possibility we have now... or it will?

I'm far to be sure, but now I'm thinking something like:

sm::process_event(evt)
{
  if(this->is_contained()) outer->process_event(evt); // assuming we
have a pointer to the outer sm...
  else process_event_with_rules(evt);
}

ok, that's upper-fwd...
;-)

Cheers!
Albert


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net