Boost logo

Boost Users :

Subject: Re: [Boost-users] Boost.MSM: Exit a composite state after an event has been fired from that composite state?
From: RaRi (degoah_at_[hidden])
Date: 2012-12-20 14:25:05


Hi Christophe!

Thanks for your fast response again.

I was thinking so solve my problem in another way, but I was again
disappointed.

My idea was to manage a global queue/vector for different event types. The
"global" queue could be used by the submachine to put internal events in
which than would be afterwards extracted from the State machine caller and
emited to the state machine by using the fsm.process_event(...) function.
but unfortunately this seems not to work too. Please consider the following
code snippet to understand me:

#include <iostream>
#include <boost/msm/back/state_machine.hpp>

#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
#include <boost/variant/variant.hpp>

namespace {
    namespace msm = boost::msm;
    namespace msmf = boost::msm::front;
    namespace mpl = boost::mpl;

    // ----- Events
    struct Event1 {};
    struct Event2 {};
    struct Event3 {};
    struct EventSub1 {};
    struct EventSub2 {};

    // ----- State machine
    struct OuterSm_:msmf::state_machine_def<OuterSm_>
    {
        struct State1_:msmf::state_machine_def<State1_>
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State1::on_entry()" << std::endl;
            }

            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                std::cout << "State1::on_exit()" << std::endl;
            }

            struct SubState1:msmf::state<> {
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm& fsm) const {
                    std::cout << "SubState1::on_entry()" << std::endl;
                }

                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) const {
                    std::cout << "SubState1::on_exit()" << std::endl;
                }
            };

            struct SubState2:msmf::state<> {
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm& a) const {
                    std::cout << "SubState2::on_entry()" << std::endl;
                }

                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) const {
                    std::cout << "SubState2::on_exit()" << std::endl;
                }
            };

            struct Exit1:msmf::exit_pseudo_state<msmf::none> {};

            // Set initial state
            typedef mpl::vector<SubState1> initial_state;
            // Transition table
            struct transition_table:mpl::vector<
               // Start Event Next Action Guard
               msmf::Row < SubState1, EventSub1, SubState2, msmf::none,
msmf::none >
> {};
        };

        struct State2:msmf::state<>
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State2::on_entry()" << std::endl;
            }

            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                std::cout << "State2::on_exit()" << std::endl;
            }

            template <class Event, class Fsm, class SourceState, class
TargetState>
            void operator()(Event const&, Fsm& f, SourceState&,
TargetState&) const
            {
                std::cout << "Do function" << std::endl;
            }
        };

        struct State3:msmf::state<>
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State3::on_entry()" << std::endl;
            }

            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                std::cout << "State3::on_exit()" << std::endl;
            }
        };

        typedef msm::back::state_machine<State1_> State1;

        // Set initial state
        typedef State2 initial_state;
        // Transition table
        struct transition_table:mpl::vector<
            // Start Event Next Action Guard
            msmf::Row < State2, Event2, State2, msmf::none, msmf::none
>,
            msmf::Row < State3, Event3, msmf::none, msmf::none,
msmf::none >
> {};
    };

    // Pick a back-end
    typedef msm::back::state_machine<OuterSm_> Osm;

    void test()
    {
       Osm osm;
       osm.start();

       std::vector< boost::variant<Event1, Event2, Event3> > vec;

       // With boost::any it also doesn't work
       // std::vector< boost::any > vec;

       vec.push_back(Event1());
       vec.push_back(Event2());
       vec.push_back(Event3());

       while(vec.size() != 0){
               osm.process_event(vec.pop_back());
       }
    }
}

int main()
{
    test();
    return 0;
}

Compiling is fine, but while running this example I get again a
BOOST_ASSERTION, cause the event type isn't known.

I think the base problem occurs in the compilation phase, due to the fact,
that the template event type of the *process_event(...)* function isn't
distinct due to the different types defined in *boost::variant<...>* as
state above in the main() function. In contrast to that the following code
snippet works fine.

....
        osm.enqueue_event(Event1());
        osm.enqueue_event(Event2());
        osm.enqueue_event(Event3());

        osm.execute_queued_events();

...

Using the *enqueue_event()* function call has unfortunately the constraint,
that for each sub-machine a own event queue is used and for each sub-machine
the call execute_queued_events has to be triggered. I don't want this. I
want to queue all possible events of the all submachines and to call
execute_queued_events function from a central position.

Do you have an idea how I could solve this issue. Does MSM provide a global
event queue? If not, it would be necessary to provide each sub-machine with
a pointer to the outermost submachine to be able to put events to the event
queue. Afterwards "execute_queued_events()" can be called by the
control-logic which encloses the overal state machine.

Thank you in advance!

Sorry für die vielen Fragen, muss jedoch abwägen, ob MSM für den produktiven
Einsatz in
einem noch zu entwickelden Software-Produkt geeignet ist.

Grüße,

RaRi

--
View this message in context: http://boost.2283326.n4.nabble.com/Boost-MSM-Exit-a-composite-state-after-an-event-has-been-fired-from-that-composite-state-tp4640341p4640414.html
Sent from the Boost - Users mailing list archive at Nabble.com.

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