Boost::MSM: Transition Priority

I try to use boost::MSM to implement a simple state machine for testing purpose. There are several events which have to be processed in the right order, so i defer the other events, which are currently not allowed. I try to defer the events in the transition table, to have one place to look for it, despite having all states to look, what events they defer. I tried to change the transition rows to change their priorities, but it didnt help. If i unkomment the anonymous transition from live_got_image to live_wait_for_image, it works as expected, but i want to transition automaticly to repeatedly enter the states live_wait_for_image/live_got_image until the ev_stop_live get sent. I expect the following output: ------------------------------ entering: fsm_master entering: not_ready no transition from state 0 on event struct `anonymous namespace'::ev_stop_live leaving: not_ready starting: live_wait_for_image leaving: live_wait_for_image starting: live_got_image leaving: live_got_image entering: not_ready but actually i get the following output: ---------------------------------------- entering: fsm_master entering: not_ready no transition from state 0 on event struct `anonymous namespace'::ev_stop_live leaving: not_ready starting: live_wait_for_image leaving: live_wait_for_image starting: live_got_image leaving: live_got_image starting: live_wait_for_image I use boost 1.57.0 and MSVC-2013 (VS-12). Could anybody get me a useful hint? Georg Here is the code: #include <iostream> // back-end #include <boost/msm/back/state_machine.hpp> //front-end #include <boost/msm/front/state_machine_def.hpp> #include <boost/msm/front/functor_row.hpp> namespace msm = boost::msm; namespace mpl = boost::mpl; namespace { using namespace boost::msm::front; // events struct ev_start_stop {}; struct ev_start_live {}; struct ev_stop_live {}; struct ev_learn {}; struct ev_load {}; struct ev_got_image { int payload; }; // front end: define the FSM structure struct fsm_master_ : public msm::front::state_machine_def<fsm_master_> { typedef int activate_deferred_events; template <class Event, class FSM> void on_entry(Event const&, FSM&) { std::cout << "entering: fsm_master" << std::endl; } template <class Event, class FSM> void on_exit(Event const&, FSM&) { std::cout << "leaving: fsm_master" << std::endl; } // the fsm states which are not sub state machines struct not_ready : public msm::front::state<> { template <class Event, class FSM> void on_entry(Event const&, FSM&) { std::cout << "entering: not_ready" << std::endl; } template <class Event, class FSM> void on_exit(Event const&, FSM&) { std::cout << "leaving: not_ready" << std::endl; } }; // The list of FSM states struct live_wait_for_image : public msm::front::state<> { template <class Event, class FSM> void on_entry(Event const&, FSM&) { std::cout << "starting: live_wait_for_image" << std::endl; } template <class Event, class FSM> void on_exit(Event const&, FSM&) { std::cout << "leaving: live_wait_for_image" << std::endl; } }; struct live_got_image : public msm::front::state<> { // here we got the image and we can check, if we need to react on an external event // otherwise transit to wait_for_image and fetch the next image template <class Event, class FSM> void on_entry(Event const&, FSM&) { std::cout << "starting: live_got_image" << std::endl; } template <class Event, class FSM> void on_exit(Event const&, FSM&) { std::cout << "leaving: live_got_image" << std::endl; } }; // --------------------------------------------------- // initial state: fsm_master_ typedef not_ready initial_state; typedef fsm_master_ l; struct transition_table : mpl::vector< // Start Event Next Action Guard // +---------------------+----------------+-------------------+-------------------+----------------+ _row < not_ready, ev_start_live, live_wait_for_image >, _row < live_wait_for_image, ev_got_image, live_got_image >, Row < live_wait_for_image, ev_stop_live, none , Defer , none >, _row < live_got_image, none, live_wait_for_image >, _row < live_got_image, ev_stop_live, not_ready > // +---------------------+----------------+-------------------+-------------------+----------------+ > {}; // Replaces the default no-transition response. template <class FSM, class Event> void no_transition(Event const& e, FSM&, int state) { std::cout << "no transition from state " << state << " on event " << typeid(e).name() << std::endl; } }; // back-end: fsm_master typedef msm::back::state_machine<fsm_master_> fsm_master; } void test() { fsm_master s; s.start(); s.process_event(ev_stop_live()); // this gets no transitioned s.process_event(ev_start_live()); // this one enters live s.process_event(ev_stop_live()); // this gets defered s.process_event(ev_got_image()); // this one enters got_image and the stop live should get processed. // now we should be in not ready again, but we are still in live_wait_for_image } int main() { test(); return 0; }

Hi,
I try to use boost::MSM to implement a simple state machine for testing purpose. There are several events which have to be processed in the right order, so i defer the other events, which are currently not allowed. I try to defer the events in the transition table, to have one place to look for it, despite having all states to look, what events they defer.
I tried to change the transition rows to change their priorities, but it didnt help. If i unkomment the anonymous transition from live_got_image to live_wait_for_image, it works as expected, but i want to transition automaticly to repeatedly enter the states live_wait_for_image/live_got_image until the ev_stop_live get sent.
I'm afraid it won't work. According to the UML standard which MSM tries to follow, anonymous transitions have higher priority than deferred events. You could use a guard in the anonymous transition to disable it if you have a deferred event in the queue, for example: struct OnlyIfNoDeferred { template<class Event, class Fsm, class SourceState, class TargetState> bool operator()(Event const &, Fsm & aFsm, SourceState &, TargetState &) { return aFsm.get_deferred_queue().empty(); } }; As we're talking about anonymous transitions, I read "repeatedly", but please be careful not to add another anonymous transition back otherwise you might get into an endless loop of anonymous transitions. HTH, Christophe

Hi,
Hi,
As we're talking about anonymous transitions, I read "repeatedly", but please be careful not to add another anonymous transition back otherwise you might get into an endless loop of anonymous transitions.
I tried your suggestion, and only this did work. struct OnlyIfNoDeferred { template<class Event, class Fsm, class SourceState, class TargetState> bool operator()(Event const &, Fsm & aFsm, SourceState &, TargetState &) { size_t s_mq = aFsm.get_message_queue().size(); size_t s_dq = aFsm.get_deferred_queue().size(); return aFsm.get_message_queue().empty(); } }; s_mq = 1 s_dq = 0 This functor does now work. I just answer and ask again, because i thought that the defered queue should be size=1 and not the message queue.... Is this a bug or is this intended behaviour?
HTH, Christophe
Thanks, Georg

Hi,
I tried your suggestion, and only this did work.
struct OnlyIfNoDeferred { template<class Event, class Fsm, class SourceState, class TargetState> bool operator()(Event const &, Fsm & aFsm, SourceState &, TargetState &) { size_t s_mq = aFsm.get_message_queue().size(); size_t s_dq = aFsm.get_deferred_queue().size(); return aFsm.get_message_queue().empty(); } };
s_mq = 1 s_dq = 0
This functor does now work. I just answer and ask again, because i thought that the defered queue should be size=1 and not the message queue.... Is this a bug or is this intended behaviour?
Sorry, I tried with the develop branch version not 1.57. It is a bug, wich I coincidentally fixed last week in the develop branch, it really has to be the deferred queue, though for your case it probably matters little. HTH, Christophe
participants (2)
-
christophe.j.henry@gmail.com
-
georg@schorsch-tech.de