Choice Pseudo State

First of all, consider the difference between junction pseudo state and choice pseudo state.
fig8.png
fig9.png
These two diagrams are similar. The only difference is that one uses junction pseudo state and the other uses choice pseudo state.

Look at the diagram that uses junction pseudo state. When Event1 occurs, guard conditions are evaluated prior to invoke the action corresponding to Event1. Hence the else branch is chosen. And then actions are invoked along with the transition sequence. The diagram above (case of junction pseudo state) indicates that the action val=1 is invoked first, and then the action ElseBranch is invoked. Consequently, val related to the action ElseBranch is equal to 1.

Then, look at the diagram that uses choice pseudo state. When Event1 occurs, guard conditions are evaluated after invoke the action corresponding to Event1. Hence the [val==1] branch is chosen. And then action Val1Branch is invoked. This means that when a transition reaches a state, the action that corresponds to the transition is evaluated one by one.

Let's see how choice pseudo state may be implemented on Boost.Msm. Boost.Msm doesn't support choice pseudo states directly but you can use the normal state instead of the choice pseudo state. The replaced model is described as the following diagram.
fig10.png
And then, translate the model above into the following code directly.
#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 {};
 
    // ----- State machine
    struct Sm1_:msmf::state_machine_def<Sm1_>
    {
        struct State1_:msmf::state<>{
            template <class Event, class Fsm, class SourceState, class TargetState>
            void operator()(Event const&, Fsm& f, SourceState&, TargetState&) const 
            {
                f.val = 0;
                std::cout << "val = " << f.val << std::endl;
            }
        };
        struct Choice_:msmf::state<>{};
 
        // Set initial state
        typedef State1_ initial_state;
 
         // Guards
        struct GuardVal1 {
            template <class Event, class Fsm, class SourceState, class TargetState>
            bool operator()(Event const&, Fsm& f, SourceState&, TargetState&) const 
            {
                if (f.val == 1) return true;
                return false;
            }
        };
         // Actions
        struct ActionVal1Assign {
            template <class Event, class Fsm, class SourceState, class TargetState>
            void operator()(Event const&, Fsm& f, SourceState&, TargetState&) const 
            {
                f.val = 1;
                std::cout << "ActionVal1Assign val = " << f.val << std::endl;
            }
        };
        struct ActionVal1Branch {
            template <class Event, class Fsm, class SourceState, class TargetState>
            void operator()(Event const&, Fsm& f, SourceState&, TargetState&) const 
            {
                std::cout << "ActionVal1Branch val = " << f.val << std::endl;
            }
        };
        struct ActionElseBranch {
            template <class Event, class Fsm, class SourceState, class TargetState>
            void operator()(Event const&, Fsm& f, SourceState&, TargetState&) const 
            {
                std::cout << "ActionElseBranch val = " << f.val << std::endl;
            }
        };
 
        // Transition table
        struct transition_table:mpl::vector<
            //          Start    Event       Next     Action            Guard
            msmf::Row < State1_, Event1,     Choice_, ActionVal1Assign, msmf::none >,
            msmf::Row < Choice_, msmf::none, State1_, ActionElseBranch, msmf::none >, // else
            msmf::Row < Choice_, msmf::none, State1_, ActionVal1Branch, GuardVal1 >
        > {};
        private:
            int val;
    };
 
    // 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());
    }
}
 
int main()
{
    test();
    return 0;
}
 
// Output:
//
// > Send Event1
// ActionVal1Assign val = 1
// ActionVal1Branch val = 1
Add a New Comment