Re: [Boost-users] [MSM] how to use a compilation firewall around inner state machines
Repost from different email client (prior ate linefeeds, sorry again). I have a state machine implemented with MSM (eUML) that currently has 80 transitions, there are two inner state machines. Compilation time is not great, but I have been dealing with it by BOOST_MSM_FAVOR_COMPILE_TIME and using parallel compilation where possible. Slow compilation time is an irritation and productivity killer, but my larger worry is that eventually the compiler will run out of memory. Especially as I will likely have to add another inner state machine with about 40 more transitions. Current we are using VS2008 but planning on moving everyone in the team to the VS2012 toolset but running under the VS2013 environment. I don't know if this will help, I doubt it. Currently compilation memory usage is up to 2.5GB per translation unit. So I would like to use a compilation firewall around the inner state machines. My plan is to implement concrete types for the inner state machines, with a process_event function: boost::msm::back::HandledEnum process_event( const boost::any & event ); Then within this function test for each event type to be handled by the inner state machine, and forward to a regular MSM state machine contained within the inner concrete type. I am hoping that this, plus on_entry and on_exit functions is about all I need to do. I expect that I will be able to get this to work, although an example on how to put a concrete wrapper around an inner state machine would be great, and importantly a list of limitations and work arounds for this technique would be helpful. My problem is that the outer state machine transition table has rows like this: exit_pt_( inner_state, inner_state_some_pseudo_exit_state ) / do_some_stuff() == outer_s2, exit_pt_( inner_state, inner_state_other_pseudo_exit_state ) / do_other_stuff() == outer_s3, If inner_state becomes a concrete type, then I don't know if this can be handled, and if so how? My best idea so far is for the inner_state to call process_event on the outer state machine and rewrite the outer machine's state transition table thus: inner_state + some_synthetic_event / do_some_stuff() == outer_s2, inner_state + other_synthetic_event / do_other_stuff() == outer_s3 The xxxx_synthetic_event's would be generated from within the inner state machine when it reaches one of the pseudo exit states. So in summary I would like to know: 1) Is there a documented example of putting a concrete wrapper around a inner state machine. 2) What is the list of limitations of doing this. e.g. exit_pt_ not working. 3) How should I deal with transitions in the outer state machine that were making use of exit_pt_ P.S. I've got to say that I think MSM is great! thanks - - Mark
Hi Mark,
I have a state machine implemented with MSM (eUML) that currently has 80 transitions, there are two inner state machines.
Compilation time is not great, but I have been dealing with it by BOOST_MSM_FAVOR_COMPILE_TIME and using parallel compilation where possible.
It's quite a hard combination for a compiler, 80 transitions, submachines and eUML. Maybe you could consider the functor front-end for such a case? It'll compile much faster.
So I would like to use a compilation firewall around the inner state machines. My plan is to implement concrete types for the inner state machines, with a process_event function:
boost::msm::back::HandledEnum process_event( const boost::any & event );
Yes, it would likely work. But quite hard to maintain after you add a couple
of events. Why not divide your big fsm into several classes (as you
suggest), each with their own fsm, but with a real interface with member
names. And you should also, if you can, hide the full submachine into the
cpp:
struct InnerFsm
{
void handleEventX();
private:
stuct Fsm_;
boost::shared_ptr
Then within this function test for each event type to be handled by the inner state machine, and forward to a regular MSM state machine contained within the inner concrete type. I am hoping that this, plus on_entry and on_exit functions is about all I need to do. I expect that I will be able to get this to work, although an example on how to put a concrete wrapper around an inner state machine would be great, and importantly a list of limitations and work arounds for this technique would be helpful.
I think you'd also lose the flag state for these submachines, though it's easily implemented. And transition conflicts (if you have one on the same event: once with the submachine as source state, one being another state in the same outer fsm). This can be implemented by adding bool member functions in the inner fsm, then adding an extra transition in your outer fsm for each conflict originating from the inner fsm, with an action calling the corresponding process_event member of the inner fsm.
My problem is that the outer state machine transition table has rows like this:
exit_pt_( inner_state, inner_state_some_pseudo_exit_state ) / do_some_stuff() == outer_s2,
exit_pt_( inner_state, inner_state_other_pseudo_exit_state ) / do_other_stuff() == outer_s3,
If inner_state becomes a concrete type, then I don't know if this can be handled, and if so how?
My best idea so far is for the inner_state to call process_event on the outer state machine and rewrite the outer machine's state transition table thus:
inner_state + some_synthetic_event / do_some_stuff() == outer_s2,
inner_state + other_synthetic_event / do_other_stuff() == outer_s3 The xxxx_synthetic_event's would be generated from within the inner state machine when it reaches one of the pseudo exit states.
If you have your own class, as shown above, you can pass from the outer to the InnerFsm class a functor (std/boost::function) or a type_erasure for a callback, thus hiding the event itself from the InnerFsm class. The callback can be a simple lambda (if you move to a C++11 compiler) [this](){this->process_event(other_synthetic_event());}
So in summary I would like to know:
1) Is there a documented example of putting a concrete wrapper around a inner state machine.
No. I will add this.
2) What is the list of limitations of doing this. e.g. exit_pt_ not working.
As said, flags, transition conflicts. I don't see more at the moment.
3) How should I deal with transitions in the outer state machine that were making use of exit_pt_
As said above, provide at construction of the inner fsm a callback.
P.S. I've got to say that I think MSM is great!
thanks :)
thanks
- - Mark
HTH, Christophe
participants (2)
-
christophe.j.henry@googlemail.com
-
Mark.Bartosik@thomsonreuters.com