Deferred Events

UML supports a deferred events function. Consider the following diagram.
fig11.png
When an event occurs in the state that has a defer description that corresponds to the event, it will be preserved. And when the transition will reach a state that doesn't have a defer description that corresponds to the deferred event, it will be invoked.
For example, when Event1 occurs twice in State1 in the diagram above, they are preserved. And then, when Event2 occurs, they are still preserved. Because State2 also has the defer description. When Event2 occurs once more, transitions occur in order of State3, State4, and State5.
Boost.Msm supports deferred events directly. To use the deferred events, you need to insert the following typedef in the definition of your state machine.
        typedef int activate_deferred_events;

And then, place the msmf::Defer into the Action field in the transition table. As with a normal action, you can write a guard function object. If you write that, the event is preserved only when the guard condition is satisfied.
        struct transition_table:mpl::vector<
            //          Start   Event   Next        Action       Guard
            msmf::Row < State1, Event1, msmf::none, msmf::Defer, msmf::none >,
            msmf::Row < State2, Event1, msmf::none, msmf::Defer, msmf::none >,

The following code corresponds to the diagram above.

#include <iostream>
#include <boost/msm/back/state_machine.hpp>
 
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
 
namespace {
    namespace msm = boost::msm;
    namespace msmf = boost::msm::front;
    namespace mpl = boost::mpl;
 
    // ----- Events
    struct Event1 {};
    struct Event2 {};
 
    // ----- State machine
    struct Sm1_:msmf::state_machine_def<Sm1_>
    {
        // States
        struct State1:msmf::state<> 
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State1::on_entry()" << std::endl;
            }
        };
        struct State2:msmf::state<> 
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State2::on_entry()" << 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;
            }
        };
        struct State4:msmf::state<> 
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State4::on_entry()" << std::endl;
            }
        };
        struct State5:msmf::state<> 
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State5::on_entry()" << std::endl;
            }
        };
        struct State6:msmf::state<> 
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State6::on_entry()" << std::endl;
            }
        };
 
        // Set initial state
        typedef State1 initial_state;
        // Enable deferred capability
        typedef int activate_deferred_events;
        // Transition table
        struct transition_table:mpl::vector<
            //          Start   Event   Next        Action       Guard
            msmf::Row < State1, Event1, msmf::none, msmf::Defer, msmf::none >,
            msmf::Row < State2, Event1, msmf::none, msmf::Defer, msmf::none >,
            msmf::Row < State1, Event2, State2,     msmf::none,  msmf::none >,
            msmf::Row < State2, Event2, State3,     msmf::none,  msmf::none >,
            msmf::Row < State3, Event1, State4,     msmf::none,  msmf::none >,
            msmf::Row < State4, Event1, State5,     msmf::none,  msmf::none >,
            msmf::Row < State5, Event1, State6,     msmf::none,  msmf::none >
        > {};
    };
 
    // Pick a back-end
    typedef msm::back::state_machine<Sm1_> Sm1;
 
    void test()
    {        
        Sm1 sm1;
        sm1.start(); 
        std::cout << "> Send Event1" << std::endl;
        sm1.process_event(Event1());
        std::cout << "> Send Event1" << std::endl;
        sm1.process_event(Event1());
        std::cout << "> Send Event2" << std::endl;
        sm1.process_event(Event2());
        std::cout << "> Send Event2" << std::endl;
        sm1.process_event(Event2());
    }
}
 
int main()
{
    test();
    return 0;
}
 
// Output:
//
// State1::on_entry()
// > Send Event1
// > Send Event1
// > Send Event2
// State2::on_entry()
// > Send Event2
// State3::on_entry()
// State4::on_entry()
// State5::on_entry()
Let's see more complicated case. An anonymous transition has higher priority than deferred events. Consider the following diagram.
fig12.png
When the Event1 occurs in State1, the event is preserved. And then, when Event2 occurs, the current state transitions to State2. State2 has two outgoing transitions. One has Event1, the other is anonymous transition. According to the priority the anonymous transition is chosen. As a result, transitions occur in order of State3 and State4.
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
 
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
 
namespace {
    namespace msm = boost::msm;
    namespace msmf = boost::msm::front;
    namespace mpl = boost::mpl;
 
    // ----- Events
    struct Event1 {};
    struct Event2 {};
 
    // ----- State machine
    struct Sm1_:msmf::state_machine_def<Sm1_>
    {
        // States
        struct State1:msmf::state<> 
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State1::on_entry()" << std::endl;
            }
        };
        struct State2:msmf::state<> 
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State2::on_entry()" << 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;
            }
        };
        struct State4:msmf::state<> 
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State4::on_entry()" << std::endl;
            }
        };
        struct State5:msmf::state<> 
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State5::on_entry()" << std::endl;
            }
        };
 
        // Set initial state
        typedef State1 initial_state;
        // Enable deferred capability
        typedef int activate_deferred_events;
        // Transition table
        struct transition_table:mpl::vector<
            //          Start   Event       Next        Action       Guard
            msmf::Row < State1, Event1,     msmf::none, msmf::Defer, msmf::none >,
            msmf::Row < State1, Event2,     State2,     msmf::none,  msmf::none >,
            msmf::Row < State2, msmf::none, State3,     msmf::none,  msmf::none >,
            msmf::Row < State3, Event1,     State4,     msmf::none,  msmf::none >,
            msmf::Row < State2, Event1,     State5,     msmf::none,  msmf::none >
        > {};
    };
 
    // Pick a back-end
    typedef msm::back::state_machine<Sm1_> Sm1;
 
    void test()
    {        
        Sm1 sm1;
        sm1.start(); 
        std::cout << "> Send Event1" << std::endl;
        sm1.process_event(Event1());
        std::cout << "> Send Event2" << std::endl;
        sm1.process_event(Event2());
    }
}
 
int main()
{
    test();
    return 0;
}
 
// Output:
//
// State1::on_entry()
// > Send Event1
// > Send Event2
// State2::on_entry()
// State3::on_entry()
// State4::on_entry()
Add a New Comment