美文网首页
Boost.Msm 介绍

Boost.Msm 介绍

作者: 守拙圆 | 来源:发表于2018-01-30 10:54 被阅读781次

    原文:Boost.Msm guide
    译者:penghuster

    1 简单状态机

    简单状态机按照如下工作流程:

    它包括一个初始化伪状态,一个正常状态和一个结束状态。如下代码是上述图表中流程的一种实现。

    #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_>
        {
            // States
            struct State1:msmf::state<> 
            {
                // Entry action
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm&) const {
                    std::cout << "State1::on_entry()" << std::endl;
                }
                // Exit action
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) const {
                    std::cout << "State1::on_exit()" << std::endl;
                }
            };
            struct End:msmf::terminate_state<> {};
     
            // Set initial state
            typedef State1 initial_state;
     
            // Transition table
            struct transition_table:mpl::vector<
                //          Start   Event   Next    Action      Guard
                msmf::Row < State1, Event1, End,    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());
        }
    }
     
    int main()
    {
        test();
        return 0;
    }
     
    // Output:
    //
    // State1::on_entry()
    // > Send Event1
    // State1::on_exit()
    

    Sm1_ 是一个状态机的定义,在 Sm1_,有两个状态,state1 和 End。初始伪状态是定义在一下代码行:
    typedef State1 initial_state;
    此初始状态类型定义意味着状态机 Sm1 从状态 State1 开始。

    考虑如下图表:

    从初始状态转变到 State1 有一个动作。为了实现这种类型的状态机,你需要额外的代码。

    A transition from an initial pseudo state to State1 has an action. To implement this kind of state machine, you need additional codes.

    2 初始状态转换的动作

    如下图表和代码展示了如何实现一个初始状态转变的动作:

    在如下代码片段中,此初始状态类型定义仅仅表明状态机从State1开始,此初始状态定义并没有引入一个初始伪状态。

    // Set initial state
            typedef State1 initial_state;
    

    为了实现从 State1 和 初始伪状态转换的转换动作,需要在代码中定义初始伪状态。Boost.Msm 不能直接支持初始伪状态,但是可以用一个正常状态来替代。则将原始图表改写为如下图表:

    你不必写此模型,此模型的目的在于帮助你更好理解下面的代码的实现过程:

    #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_>
        {
            // States
            struct Init:msmf::state<> {};
            struct State1:msmf::state<> 
            {
                // Entry action
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm&) {
                    std::cout << "State1::on_entry()" << std::endl;
                }
                // Exit action
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) {
                    std::cout << "State1::on_exit()" << std::endl;
                }
            };
     
            // Set initial state
            typedef Init initial_state;
     
            // Actions
            struct InitAction {
                template <class Event, class Fsm, class SourceState, class TargetState>
                void operator()(Event const&, Fsm&, SourceState&, TargetState&) const
                {
                    std::cout << "InitAction()" << std::endl;
                }
            };
     
            // Transition table
            struct transition_table:mpl::vector<
                //          Start   Event       Next    Action      Guard
                msmf::Row < Init,   msmf::none, State1, InitAction, msmf::none >,
                msmf::Row < State1, Event1,     State1, 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());
        }
    }
     
    int main()
    {
        test();
        return 0;
    }
     
    // Output:
    //
    // InitAction()
    // State1::on_entry()
    // > Send Event1
    // State1::on_exit()
    // State1::on_entry()
    

    看下面代码行:
    msmf::Row < Init, msmf::none, State1, InitAction, msmf::none >,
    这是一个状态转换表行。这里最重要的是其事件为msmf::none。这意味着当状态机处于Init状态时,自动触发从 Init 到 state1 的转换。

    3 明确地指定的事件句柄

    Boost.Msm的事件句柄能够重载。on_entry 和 on_exit 动作的句柄可以通过事件类型匹配。守卫条件和动作因子能够通过 Event,SourceState 和 TargetState 来匹配。

    让我们看如下图表:

    所有的转变都有同样的守卫条件和动作因子。
    以上图表的代码实现如下:

    #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 {};
        struct InitialEvent {};
        // ----- State machine
        struct Sm1_:msm::front::state_machine_def<Sm1_>
        {
            typedef InitialEvent initial_event;
            // States
            struct State1:msm::front::state<> 
            {
                // Entry action
                template <class Fsm>
                void on_entry(InitialEvent const&, Fsm&) const {
                    std::cout << "State1::on_entry(InitialEvent)" << std::endl;
                }
                template <class Fsm>
                void on_entry(Event1 const&, Fsm&) const {
                    std::cout << "State1::on_entry(Event1)" << std::endl;
                }
                template <class Fsm>
                void on_entry(Event2 const&, Fsm&) const {
                    std::cout << "State1::on_entry(Event2)" << std::endl;
                }
                // Exit action
                template <class Fsm>
                void on_exit(Event1 const&, Fsm&) const {
                    std::cout << "State1::on_exit(Event1)" << std::endl;
                }
                template <class Fsm>
                void on_exit(Event2 const&, Fsm&) const {
                    std::cout << "State1::on_exit(Event2)" << std::endl;
                }
            };
            struct State2:msm::front::state<> 
            {
                // Entry action
                template <class Fsm>
                void on_entry(Event1 const&, Fsm&) const {
                    std::cout << "State2::on_entry(Event1)" << std::endl;
                }
                template <class Fsm>
                void on_entry(Event2 const&, Fsm&) const {
                    std::cout << "State2::on_entry(Event2)" << std::endl;
                }
                // Exit action
                template <class Fsm>
                void on_exit(Event1 const&, Fsm&) const {
                    std::cout << "State2::on_exit(Event1)" << std::endl;
                }
                template <class Fsm>
                void on_exit(Event2 const&, Fsm&) const {
                    std::cout << "State2::on_exit(Event2)" << std::endl;
                }
            };
     
            struct Action1 {
                template <class Fsm>
                void operator()(Event1 const& e, Fsm&, State1&, State2&) const
                {
                    std::cout << "Action1(Event1, Fsm, State1, State2)" << std::endl;
                }
                template <class Fsm>
                void operator()(Event2 const& e, Fsm&, State1&, State2&) const
                {
                    std::cout << "Action1(Event2, Fsm, State1, State2)" << std::endl;
                }
                template <class Fsm>
                void operator()(Event1 const& e, Fsm&, State2&, State1&) const
                {
                    std::cout << "Action1(Event1, Fsm, State2, State1)" << std::endl;
                }
                template <class Fsm>
                void operator()(Event2 const& e, Fsm&, State2&, State1&) const
                {
                    std::cout << "Action1(Event2, Fsm, State2, State1)" << std::endl;
                }
            };
     
            struct Guard1 {
                template <class Fsm>
                bool operator()(Event1 const& e, Fsm&, State1&, State2&) const
                {
                    std::cout << "Guard1(Event1, Fsm, State1, State2)" << std::endl;
                    return true;
                }
                template <class Fsm>
                bool operator()(Event2 const& e, Fsm&, State1&, State2&) const
                {
                    std::cout << "Guard1(Event2, Fsm, State1, State2)" << std::endl;
                    return true;
                }
                template <class Fsm>
                bool operator()(Event1 const& e, Fsm&, State2&, State1&) const
                {
                    std::cout << "Guard1(Event1, Fsm, State2, State1)" << std::endl;
                    return true;
                }
                template <class Fsm>
                bool operator()(Event2 const& e, Fsm&, State2&, State1&) const
                {
                    std::cout << "Guard1(Event2, Fsm, State2, State1)" << std::endl;
                    return true;
                }
            };
     
            // Set initial state
            typedef State1 initial_state;
     
            // Transition table
            struct transition_table:mpl::vector<
                //          Start   Event   Next    Action   Guard
                msmf::Row < State1, Event1, State2, Action1, Guard1 >,
                msmf::Row < State1, Event2, State2, Action1, Guard1 >,
                msmf::Row < State2, Event1, State1, Action1, Guard1 >,
                msmf::Row < State2, Event2, State1, Action1, Guard1 >
            > {};
        };
     
        // 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(InitialEvent)
    // > Send Event1
    // Guard1(Event1, Fsm, State1, State2)
    // State1::on_exit(Event1)
    // Action1(Event1, Fsm, State1, State2)
    // State2::on_entry(Event1)
    // > Send Event1
    // Guard1(Event1, Fsm, State2, State1)
    // State2::on_exit(Event1)
    // Action1(Event1, Fsm, State2, State1)
    // State1::on_entry(Event1)
    // > Send Event2
    // Guard1(Event2, Fsm, State1, State2)
    // State1::on_exit(Event2)
    // Action1(Event2, Fsm, State1, State2)
    // State2::on_entry(Event2)
    // > Send Event2
    // Guard1(Event2, Fsm, State2, State1)
    // State2::on_exit(Event2)
    // Action1(Event2, Fsm, State2, State1)
    // State1::on_entry(Event2)
    

    当你不想关心具体的事件、原状态和目标状态时,你能用如下模板参数:

            struct State1:msm::front::state<> 
            {
                // Entry action
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm&) const {
                    std::cout << "State1::on_entry()" << std::endl;
                }
            };
     
            // Actions
            struct Action1 {
                template <class Event, class Fsm, class SourceState, class TargetState>
                void operator()(Event const&, Fsm&, SourceState&, TargetState&) const 
                {
                    std::cout << "Action1()" << std::endl;
                }
            }
    

    4 自转变和内部转变

    Event1/Action1 是一个自转变,Event2/Action2 是一个内部转变。当内部转变发生时,entry 和 exit 动作不会被调用。与此对比,自转变会引起 entry 和 exit 的调用。

    #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<> 
            {
                // Entry action
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm&) const {
                    std::cout << "State1::on_entry()" << std::endl;
                }
                // Exit action
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) const {
                    std::cout << "State1::on_exit()" << std::endl;
                }
            };
     
            // Set initial state
            typedef State1 initial_state;
     
            // Actions
            struct Action1 {
                template <class Event, class Fsm, class SourceState, class TargetState>
                void operator()(Event const&, Fsm&, SourceState&, TargetState&) const 
                {
                    std::cout << "Action1()" << std::endl;
                }
            };
            struct Action2 {
                template <class Event, class Fsm, class SourceState, class TargetState>
                void operator()(Event const&, Fsm&, SourceState&, TargetState&) const 
                {
                    std::cout << "Action2()" << std::endl;
                }
            };
     
            // Transition table
            struct transition_table:mpl::vector<
                //          Start   Event   Next        Action      Guard
                msmf::Row < State1, Event1, State1,     Action1,    msmf::none >,
                msmf::Row < State1, Event2, msmf::none, Action2,    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
    // State1::on_exit()
    // Action1()
    // State1::on_entry()
    // > Send Event2
    // Action2()
    

    为了描述自转变,设置 Start 和 Next 为同样的状态在状态转换表中。而对于内部转变,设置 Next 为 none。none是被定义在 boost::msm::front。

    // Transition table
            struct transition_table:mpl::vector<
                //          Start   Event   Next        Action      Guard
                // Self transition
                msmf::Row < State1, Event1, State1,     Action1,    msmf::none >,
                // Internal transition
                msmf::Row < State1, Event2, msmf::none, Action2,    msmf::none >
            > {};
    

    5 两种不同实现内部转变得方式

    为了实现内部转换有两种不同方式。一种是在状态机中利用正常转变表并设置其 Next 状态为 none。此方法得优势在于此转变与其它转变放在一起,增强了其易读性。

    另一种方式是使用内部转变表,此表仅仅用于内部转变。该方法允许我们重用内部转变和状态重用。另外内部状态转换表优先于正常状态转换表。

    #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_machine_def<State1_>
            {
                 // Guards
                struct InternalGuard1 {
                    template <class Event, class Fsm, class SourceState, class TargetState>
                    bool operator()(Event const&, Fsm&, SourceState&, TargetState&) const 
                    {
                        std::cout << "Internal Transition Table's Guard1" << std::endl;
                        return false;
                    }
                };
                struct InternalGuard2 {
                    template <class Event, class Fsm, class SourceState, class TargetState>
                    bool operator()(Event const&, Fsm&, SourceState&, TargetState&) const 
                    {
                        std::cout << "Internal Transition Table's Guard2" << std::endl;
                        return false;
                    }
                };
     
                // Internal Transition table
                struct internal_transition_table:mpl::vector<
                    //               Event   Action      Guard
                    msmf::Internal < Event1, msmf::none, InternalGuard1 >,
                    msmf::Internal < Event1, msmf::none, InternalGuard2 >
                > {};        
            };
     
            // Set initial state
            typedef State1_ initial_state;
     
             // Guards
            struct Guard1 {
                template <class Event, class Fsm, class SourceState, class TargetState>
                bool operator()(Event const&, Fsm&, SourceState&, TargetState&) const 
                {
                    std::cout << "Transition Table's Guard1" << std::endl;
                    return false;
                }
            };
            struct Guard2 {
                template <class Event, class Fsm, class SourceState, class TargetState>
                bool operator()(Event const&, Fsm&, SourceState&, TargetState&) const 
                {
                    std::cout << "Transition Table's Guard2" << std::endl;
                    return false;
                }
            };
     
            // Transition table
            struct transition_table:mpl::vector<
                //          Start    Event   Next        Action      Guard
                msmf::Row < State1_, Event1, msmf::none, msmf::none, Guard1 >,
                msmf::Row < State1_, Event1, msmf::none, msmf::none, Guard2 >
            > {};
        };
     
        // 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
    // Internal Transition Table's Guard2
    // Internal Transition Table's Guard1
    // Transition Table's Guard2
    // Transition Table's Guard1
    

    6 连接点伪状态

    Boost.Msm 不能直接支持连接点伪状态。如果想实现连接点伪状态,必须要转变 UML 模型。此转变过程十分简单。从于连接点伪状态相关的转变中分离每个独立的转变。
    例如,关于如下图表:

    它可以被转换为以下图表:

    #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 {
            Event1(int val):val(val) {}
            int val;
        };
     
        // ----- State machine
        struct Sm1_:msmf::state_machine_def<Sm1_>
        {
            struct State1_:msmf::state_machine_def<State1_>{};
     
            // Set initial state
            typedef State1_ initial_state;
     
             // Guards
            struct Guard1 {
                template <class Event, class Fsm, class SourceState, class TargetState>
                bool operator()(Event const& e, Fsm&, SourceState&, TargetState&) const 
                {
                    if (e.val == 1) return true;
                    return false;
                }
            };
            struct Guard2 {
                template <class Event, class Fsm, class SourceState, class TargetState>
                bool operator()(Event const& e, Fsm&, SourceState&, TargetState&) const 
                {
                    if (e.val == 2) return true;
                    return false;
                }
            };
             // Actions
            struct Action1 {
                template <class Event, class Fsm, class SourceState, class TargetState>
                void operator()(Event const&, Fsm&, SourceState&, TargetState&) const 
                {
                    std::cout << "Action1" << std::endl;
                }
            };
            struct Action2 {
                template <class Event, class Fsm, class SourceState, class TargetState>
                void operator()(Event const&, Fsm&, SourceState&, TargetState&) const 
                {
                    std::cout << "Action2" << std::endl;
                }
            };
     
            // Transition table
            struct transition_table:mpl::vector<
                //          Start    Event   Next     Action   Guard
                msmf::Row < State1_, Event1, State1_, Action1, Guard1 >,
                msmf::Row < State1_, Event1, State1_, Action2, Guard2 >
            > {};
        };
     
        // back-end
        typedef msm::back::state_machine<Sm1_> Sm1;
     
        void test()
        {
            Sm1 sm1;
            sm1.start(); 
            std::cout << "> Send Event1(1)" << std::endl;
            sm1.process_event(Event1(1));
            std::cout << "> Send Event1(2)" << std::endl;
            sm1.process_event(Event1(2));
        }
    }
     
    int main()
    {
        test();
        return 0;
    }
     
    // Output:
    //
    // > Send Event1(1)
    // Action1
    // > Send Event1(2)
    // Action2
    

    6.1 if/else 分支

    有时可能需要用 if/else分支。考虑如下图表:

    Boost.Msm 不能直接支持 if/else 分支。如早些时候所提到,转变表和内部转变表是最低行到最高行逐步评估。这意味着你可以通过状态转变行在转变组中的位置来实现 if/else 分支。在else行的 guard 是 none。如下的状态转变表:

     // Transition table
            struct transition_table:mpl::vector<
                //          Start    Event   Next     Action   Guard
                msmf::Row < State1_, Event1, State1_, Action2, msmf::none >, // else
                msmf::Row < State1_, Event1, State1_, Action1, Guard1 >
            > {};
    

    7 选择伪状态

    首先,考虑下连接点伪状态和选择伪状态的不同。

    这两个图表很相似。其唯一的差别在于一个用连接伪状态,另一个用选择伪状态。先来看图1,当 Event1 发生时,根据状态表中顺序选择首先执行哪个分支,且守卫条件的评估应该优先于Event1的动作调用,随后根据守卫条件的评估结果来决定是否调用对应分支的Event1的动作调用与否。若val = 1,则两个分支都的动作根据转换表中的顺序进行先后调用。(注意:与上一节中if/else分支的选择类似在val != 1是方能达到二者选其一的效果。)

    然后,来看图2中的选择伪状态。当 Event1 发生时,在 Event1/val=1 的相应动作调用后将评估守卫条件。因此 val==1 分支被选择,随后 Val1Action 被调用。这意味着当此状态转换完成(转换到choice状态)后,相应的转换动作将被一个一个被评估是否进行条用。

    接下来,看看选择伪状态在 Boost.Msm 中如何实现。Boost.Msm 不直接支持选择伪状态,但是可以用正常状态替代选择伪状态。替换后如下图表中所描述。

    以下是对上述状态转换图表的具体代码实现:

    #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
    

    8 延时事件

    UML 支持延时事件功能。参见如下图表。

    在某个状态中有一个defer描述的事件发生时,此事件将被预存。直到转换到一个没有此事件延时描述的状态时,此事件将被掉调用。

    例如,在如上图表中,在 State1 发生两次 Event1,都被预存。然后,Event2 发生,由于 state2 存在 event1/defer 描述,故两个 Event1 仍然被缓存。当Event2 再次发生时,状态将按照 state3,state4 和 state5逐步变化。

    Boost.Msm 可以直接支持延时事件。为了使用延时事件,需要在状态机定义中插入如下类型定义。
    typedef int activate_deferred_events;
    然后,放置 msmf::Defer 到状态转换表的 Action 列。作为一个正常的动作,也可为其添加你守卫条件。如果守卫条件存在,则只有在守卫条件满足时事件才会预存。

            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 >,
    

    下面代码时对于图表的具体实现。

    #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()
    

    让我们来看一个更复杂的例子。一个匿名的状态转换比延时事件更高的优先级。考虑如下图表。

    当在 State1 发生 Event1时,此事件将被预存。然后 Event2发生,当前状态转变为 state2。state2 有两个将要发生的转换,一个是 Event1,另一个是匿名转变。匿名转变优先被选择。因此,接下来的状态变化为 是 state3 和 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()
    

    9 子状态机

    9.1 组合状态和子状态机

    Boost.Msm 支持组合装填和子状态机。参见如下图表,State1 是一个包含两个状态的组合状态。其对应的代码实现如下。

    命名规则

    在描述代码之前,先介绍一下命名规则,Name_(以下划线结尾的状态名)是一个继承于 state_machine_def 类模板的状态名。
    struct State1_:msmf::state_machine_def<State1_>
    Name(不以下划线结尾的状态名)是一个非继承于此的状态名。
    struct State2:msmf::state<>
    Name 也用于 Boost.Msm 有一个Name_参数的后端模板。
    typedef msm::back::state_machine<State1_> State1;

    让我们看看上面图表的代码实现。

    #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/static_assert.hpp>
     
    namespace {
        namespace msm = boost::msm;
        namespace msmf = boost::msm::front;
        namespace mpl = boost::mpl;
     
        // ----- Events
        struct Event1 {};
        struct Event2 {};
        struct Event3 {};
     
        // ----- 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 {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                    std::cout << "State1::on_entry()" << std::endl;
                }
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) const {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                    std::cout << "State1::on_exit()" << std::endl;
                }
     
                struct SubState1:msmf::state<> {
                    template <class Event,class Fsm>
                    void on_entry(Event const&, Fsm&) const {
                        BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, State1_>::value));
                        std::cout << "SubState1::on_entry()" << std::endl;
                    }
                    template <class Event,class Fsm>
                    void on_exit(Event const&, Fsm&) const {
                        BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, State1_>::value));
                        std::cout << "SubState1::on_exit()" << std::endl;
                    }
                };
                struct SubState2:msmf::state<> {
                    template <class Event,class Fsm>
                    void on_entry(Event const&, Fsm&) const {
                        BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, State1_>::value));
                        std::cout << "SubState2::on_entry()" << std::endl;
                    }
                    template <class Event,class Fsm>
                    void on_exit(Event const&, Fsm&) const {
                        BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, State1_>::value));
                        std::cout << "SubState2::on_exit()" << std::endl;
                    }
                };
     
                // Set initial state
                typedef mpl::vector<SubState1> initial_state;
                // Transition table
                struct transition_table:mpl::vector<
                    //          Start      Event   Next       Action      Guard
                    msmf::Row < SubState1, Event2, SubState2, msmf::none, msmf::none >,
                    msmf::Row < SubState2, Event3, SubState1, msmf::none, msmf::none >
                    > {};
            };
            struct State2:msmf::state<>
            {
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm&) const {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                    std::cout << "State2::on_entry()" << std::endl;
                }
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) const {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                    std::cout << "State2::on_exit()" << std::endl;
                }
            };
     
            typedef msm::back::state_machine<State1_> State1;
     
            // Set initial state
            typedef State1 initial_state;
            // Transition table
            struct transition_table:mpl::vector<
                //          Start   Event   Next    Action      Guard
                msmf::Row < State1, Event1, State2, msmf::none, msmf::none >
            > {};
        };
     
        // Pick a back-end
        typedef msm::back::state_machine<OuterSm_> Osm;
     
        void test()
        {        
            Osm osm;
            osm.start(); 
     
            std::cout << "> Send Event2()" << std::endl;
            osm.process_event(Event2());
            std::cout << "> Send Event1()" << std::endl;
            osm.process_event(Event1());
        }
    }
     
    int main()
    {
        test();
        return 0;
    }
    // Output:
    //
    // State1::on_entry()
    // SubState1::on_entry()
    // > Send Event2()
    // SubState1::on_exit()
    // SubState2::on_entry()
    // > Send Event1()
    // SubState2::on_exit()
    // State1::on_exit()
    // State2::on_entry()
    

    为了实现组合状态,继承 state_machine_def 类模板按照其父状态机相同的方式。
    struct State1_:msmf::state_machine_def<State1_>
    然后,连接到后台状态机模板。
    typedef msm::back::state_machine<State1_> State1;
    在父状态机的状态转换表中,可以使用后台状态。

            // Transition table
            struct transition_table:mpl::vector<
                //          Start   Event   Next    Action      Guard
                msmf::Row < State1, Event1, State2, msmf::none, msmf::none >
            > {};
    

    下面图表是子状态机的样例,这些图表与上面所讲的组合状态有相同的行为。子状态机的状态相对于组合状态其重用性更好。例如,你能重用StateSub 作为State2的子状态机。

    下面是具体代码实现:

    #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/static_assert.hpp>
     
    namespace {
        namespace msm = boost::msm;
        namespace msmf = boost::msm::front;
        namespace mpl = boost::mpl;
     
        // ----- Events
        struct Event1 {};
        struct Event2 {};
        struct Event3 {};
     
        // ----- State machine
        struct StateSub_:msmf::state_machine_def<StateSub_>
        {
            struct SubState1:msmf::state<> {
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm&) const {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSub_>::value));
                    std::cout << "SubState1::on_entry()" << std::endl;
                }
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) const {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSub_>::value));
                    std::cout << "SubState1::on_exit()" << std::endl;
                }
            };
            struct SubState2:msmf::state<> {
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm&) const {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSub_>::value));
                    std::cout << "SubState2::on_entry()" << std::endl;
                }
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) const {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSub_>::value));
                    std::cout << "SubState2::on_exit()" << std::endl;
                }
            };
     
            // Set initial state
            typedef mpl::vector<SubState1> initial_state;
            // Transition table
            struct transition_table:mpl::vector<
                //          Start      Event   Next       Action      Guard
                msmf::Row < SubState1, Event2, SubState2, msmf::none, msmf::none >,
                msmf::Row < SubState2, Event3, SubState1, msmf::none, msmf::none >
            > {};
        };
        typedef msm::back::state_machine<StateSub_> StateSub;
        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 {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                    std::cout << "State1::on_entry()" << std::endl;
                }
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) const {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                    std::cout << "State1::on_exit()" << std::endl;
                }
                struct Sub_:StateSub {};
                typedef Sub_ initial_state;
            };
            // Pick a back-end
            typedef msm::back::state_machine<State1_> State1;
            struct State2:msmf::state<>
            {
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm&) const {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                    std::cout << "State2::on_entry()" << std::endl;
                }
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) const {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                    std::cout << "State2::on_exit()" << std::endl;
                }
            };
            // Set initial state
            typedef State1 initial_state;
            // Transition table
            struct transition_table:mpl::vector<
                //          Start   Event   Next    Action      Guard
                msmf::Row < State1, Event1, State2, msmf::none, msmf::none >
            > {};
        };
     
        // Pick a back-end
        typedef msm::back::state_machine<OuterSm_> Osm;
     
        void test()
        {        
            Osm osm;
            osm.start(); 
     
            std::cout << "> Send Event2()" << std::endl;
            osm.process_event(Event2());
            std::cout << "> Send Event1()" << std::endl;
            osm.process_event(Event1());
        }
    }
     
    int main()
    {
        test();
        return 0;
    }
     
    // Output:
    //
    // State1::on_entry()
    // SubState1::on_entry()
    // > Send Event2()
    // SubState1::on_exit()
    // SubState2::on_entry()
    // > Send Event1()
    // SubState2::on_exit()
    // State1::on_exit()
    // State2::on_entry()
    

    在 State1_的定义中,内嵌 Sub_ 通过继承 StateSub 的方式定义,并将其设置为子状态机的初始状态。

           struct State1_:msmf::state_machine_def<State1_>
            {
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm&) const {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                    std::cout << "State1::on_entry()" << std::endl;
                }
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) const {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                    std::cout << "State1::on_exit()" << std::endl;
                }
                struct Sub_:StateSub {};
                typedef Sub_ initial_state;
            };
    
    在子状态中哪个状态机是可用的?

    事件句柄能够获取包含其状态的最内层的状态机。代码中 BOOST_STATIC_ASSERT 检查语句。但是请注意,此处 State1_::on_entry(Event const&, Fsm&) 的引用是 OuterSm_,而不是 State1_,因为 State1_ 包含在 OuterSm_ 内。

    9.2 退出伪状态

    有时我们想要从子状态机中退出。Boost.Msm 支持进入和退出伪状态,但是子状态机不支持结束状态。可以通过下面图表代替子状态机结束状态。

    在以下图表中则使用退出伪状态。

    让我们看看以上图表实现得相应代码。

    #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 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&) 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 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, Event1, Exit1, 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;
                }
            };
     
            typedef msm::back::state_machine<State1_> State1;
     
            // Set initial state
            typedef State1 initial_state;
            // Transition table
            struct transition_table:mpl::vector<
                //          Start             Event       Next    Action      Guard
                msmf::Row < State1::exit_pt
                            <State1_::Exit1>, msmf::none, State2, msmf::none, msmf::none >
            > {};
        };
     
        // Pick a back-end
        typedef msm::back::state_machine<OuterSm_> Osm;
     
        void test()
        {        
            Osm osm;
            osm.start(); 
     
            std::cout << "> Send Event1()" << std::endl;
            osm.process_event(Event1());
        }
    }
     
    int main()
    {
        test();
        return 0;
    }
     
    // Output:
    //
    // State1::on_entry()
    // SubState1::on_entry()
    // > Send Event1()
    // SubState1::on_exit()
    // State1::on_exit()
    // State2::on_entry()
    

    为了实现退出点伪状态。定义一个继承于 exit_pseudo_state 的类。
    struct Exit1:msmf::exit_pseudo_state<msmf::none> {};
    在这个子状态机中,你可以像正常状态一样去使用它。

                // Transition table
                struct transition_table:mpl::vector<
                    //          Start      Event   Next   Action      Guard
                    msmf::Row < SubState1, Event1, Exit1, msmf::none, msmf::none >
                    > {};
    

    在父状态机中,你可以按照如下方式表示子状态机的退出伪状态。
    SBEN::exit_pt<SFEN::SEPN>
    SBEN 表示 Sub-machine's back-end name
    SFEN 表示 Sub-machine's front-end name
    SEPN 表示 Sub-machine's exit point pseudo state name。

    退出伪状态的事件转换

    我们经常想知道子状态机的退出状态。按照 UML 的规范,为了实现此目标,我们将退出点伪状态分离开来。
    例如: ExitSuccess 和 ExitFailure

    Boost.Msm 提供更灵活的方法。exit_pseudo_state 类模板有一个模板参数。这是一个转换的事件。父状态机可以获取此事件。参见如下图表:

    事件 Before 被转换为事件 After,并且父状态机能够获取事件 After。这意味着从子状态机传递任何信息到父状态机。当然事件 Before 必须是可转换为 After。典型地,我们准备为 After 类添加一个转换构造函数。
    下面是上面图表相应的代码实现;

    #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 Before {
            Before(int param_):param(param_) {}
            int param; 
        };
        struct After {
            After(Before const& b):param(b.param) {}
            int param;
        };
     
        // ----- State machine
        struct OuterSm_:msmf::state_machine_def<OuterSm_>
        {
            struct State1_:msmf::state_machine_def<State1_>
            {
                struct SubState1:msmf::state<> {};
                struct Exit1:msmf::exit_pseudo_state<After> {};
     
                // Set initial state
                typedef mpl::vector<SubState1> initial_state;
                // Transition table
                struct transition_table:mpl::vector<
                    //          Start      Event   Next   Action      Guard
                    msmf::Row < SubState1, Before, Exit1, msmf::none, msmf::none >
                    > {};
            };
            struct State2:msmf::state<>
            {
                template <class Event,class Fsm>
                void on_entry(Event const& e, Fsm&) const {
                    std::cout << "State2::on_entry()" << std::endl;
                    std::cout << "Event param = " << e.param << std::endl;
                }
            };
     
            typedef msm::back::state_machine<State1_> State1;
     
            // Set initial state
            typedef State1 initial_state;
            // Transition table
            struct transition_table:mpl::vector<
                //          Start             Event  Next    Action      Guard
                msmf::Row < State1::exit_pt
                            <State1_::Exit1>, After, State2, msmf::none, msmf::none >
            > {};
        };
     
        // Pick a back-end
        typedef msm::back::state_machine<OuterSm_> Osm;
     
        void test()
        {        
            Osm osm;
            osm.start(); 
     
            std::cout << "> Send Before(42)" << std::endl;
            osm.process_event(Before(42));
        }
    }
     
    int main()
    {
        test();
        return 0;
    }
     
    // Output:
    //
    // > Send Before(42)
    // State2::on_entry()
    // Event param = 42
    

    9.3 进入点伪状态

    有三种方法实现 UML 的进入点伪状态:

    1. 使用 msm::front::entry_pseudo_state, msm::front::entry_pt 和boost::any。

    2. 使用 msm::front::entry_pseudo_state, msm::front::entry_pt 和 outer event.

    3. 使用 msm::front::explicit_entry, msm::front::direct 和 none.

    我推荐第 1 种方法,因为此方法直接能够将此模型映射到代码。Boost.Msm 从1.51.0 开始支持 boost::any 作为事件使用。如果你使用此版本或更新的版本,则最好使用方法1。否则,你就需要根据以下原则来选择方法 2 或方法 3:
    如果子状态机想要知道进入点伪状态的触发事件,选择方法 2。 否则选择方法 3。方法 2 中的引入了子状态机对于父状态机的依赖,而方法3则不存在此依赖。

    以下是相关的代码详细实现

    1. 使用 msm::front::entry_pseudo_state, msm::front::entry_pt 和boost::any。

    #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 OuterEvent {};
        struct Event1 {};
     
        // ----- State machine
        struct OuterSm_:msmf::state_machine_def<OuterSm_>
        {
            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_machine_def<State2_>
            {
                struct SubState1:msmf::state<> {
                    template <class Event,class Fsm>
                    void on_entry(Event const&, Fsm&) const {
                        std::cout << "SubState1::on_entry()" << std::endl;
                    }
                };
                struct SubState2:msmf::state<> {
                    template <class Event,class Fsm>
                    void on_entry(Event const&, Fsm&) const {
                        std::cout << "SubState2::on_entry()" << std::endl;
                    }
                };
                struct Entry1:msmf::entry_pseudo_state<> {}; // === entry_pseudo_state
                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 < Entry1,    boost::any, SubState2, msmf::none, msmf::none >, // === boost::any
                    msmf::Row < SubState1, Event1,     Exit1,     msmf::none, msmf::none >,
                    msmf::Row < SubState2, Event1,     Exit1,     msmf::none, msmf::none >
                    > {};
            };
     
            typedef msm::back::state_machine<State2_> State2;
     
            // Set initial state
            typedef State1 initial_state;
            // Transition table
            struct transition_table:mpl::vector<
                //          Start   Event       Next               Action      Guard
                msmf::Row < State1, OuterEvent, State2::entry_pt                             // === entry_pt
                                                <State2_::Entry1>, msmf::none, msmf::none >
            > {};
        };
     
        // Pick a back-end
        typedef msm::back::state_machine<OuterSm_> Osm;
     
        void test()
        {        
            Osm osm;
            osm.start(); 
     
            std::cout << "> Send OuterEvent()" << std::endl;
            osm.process_event(OuterEvent());
        }
    }
     
    int main()
    {
        test();
        return 0;
    }
    

    2. 使用 msm::front::entry_pseudo_state, msm::front::entry_pt 和 outer event.

    #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 OuterEvent {};
        struct Event1 {};
     
        // ----- State machine
        struct OuterSm_:msmf::state_machine_def<OuterSm_>
        {
            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_machine_def<State2_>
            {
                struct SubState1:msmf::state<> {
                    template <class Event,class Fsm>
                    void on_entry(Event const&, Fsm&) const {
                        std::cout << "SubState1::on_entry()" << std::endl;
                    }
                };
                struct SubState2:msmf::state<> {
                    template <class Event,class Fsm>
                    void on_entry(Event const&, Fsm&) const {
                        std::cout << "SubState2::on_entry()" << std::endl;
                    }
                };
                struct Entry1:msmf::entry_pseudo_state<> {};  // === entry_pseudo_state 
                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 < Entry1,    OuterEvent, SubState2, msmf::none, msmf::none >, // === OuterEvent
                    msmf::Row < SubState1, Event1,     Exit1,     msmf::none, msmf::none >,
                    msmf::Row < SubState2, Event1,     Exit1,     msmf::none, msmf::none >
                    > {};
            };
     
            typedef msm::back::state_machine<State2_> State2;
     
            // Set initial state
            typedef State1 initial_state;
            // Transition table
            struct transition_table:mpl::vector<
                //          Start   Event       Next               Action      Guard
                msmf::Row < State1, OuterEvent, State2::entry_pt                            // === entry_pt
                                                <State2_::Entry1>, msmf::none, msmf::none >
            > {};
        };
     
        // Pick a back-end
        typedef msm::back::state_machine<OuterSm_> Osm;
     
        void test()
        {        
            Osm osm;
            osm.start(); 
     
            std::cout << "> Send OuterEvent()" << std::endl;
            osm.process_event(OuterEvent());
        }
    }
     
    int main()
    {
        test();
        return 0;
    }
    

    Entry1 的进入事件必须可转变为 Entry1 的出口事件,在以下样例中,进入事件和出口事件都是 Outer Event。

      // Transition table
            struct transition_table:mpl::vector<
                //          Start   Event       Next               Action      Guard
                msmf::Row < State1, OuterEvent, State2::entry_pt       // === entry_pt
                                                <State2_::Entry1>, msmf::none, msmf::none >
            > {};
    
    // Transition table
                struct transition_table:mpl::vector<
                    //          Start      Event       Next       Action      Guard
                    msmf::Row < Entry1,    OuterEvent, SubState2, msmf::none, msmf::none >, // === OuterEvent
                    msmf::Row < SubState1, Event1,     Exit1,     msmf::none, msmf::none >,
                    msmf::Row < SubState2, Event1,     Exit1,     msmf::none, msmf::none >
                    > {};
    

    请注意一个重要例外情况。任何事件都能够转换为msm::front::none,因此,msm::front::none 不能够用作 Entry1 的出口事件,如此能够通过编译,但是可能发生非预期行为。

    3. 使用 msm::front::explicit_entry, msm::front::direct 和 none.

    #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 OuterEvent {};
        struct Event1 {};
     
        // ----- State machine
        struct OuterSm_:msmf::state_machine_def<OuterSm_>
        {
            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_machine_def<State2_>
            {
                struct SubState1:msmf::state<> {
                    template <class Event,class Fsm>
                    void on_entry(Event const&, Fsm&) const {
                        std::cout << "SubState1::on_entry()" << std::endl;
                    }
                };
                struct SubState2:msmf::state<> {
                    template <class Event,class Fsm>
                    void on_entry(Event const&, Fsm&) const {
                        std::cout << "SubState2::on_entry()" << std::endl;
                    }
                };
                struct Entry1:msmf::state<>, msmf::explicit_entry<> {}; // === explicit_entry
                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 < Entry1,    msmf::none, SubState2, msmf::none, msmf::none >, // === none
                    msmf::Row < SubState1, Event1,     Exit1,     msmf::none, msmf::none >,
                    msmf::Row < SubState2, Event1,     Exit1,     msmf::none, msmf::none >
                    > {};
            };
     
            typedef msm::back::state_machine<State2_> State2;
     
            // Set initial state
            typedef State1 initial_state;
            // Transition table
            struct transition_table:mpl::vector<
                //          Start   Event       Next               Action      Guard
                msmf::Row < State1, OuterEvent, State2::direct                               // === direct
                                                <State2_::Entry1>, msmf::none, msmf::none >
            > {};
        };
     
        // Pick a back-end
        typedef msm::back::state_machine<OuterSm_> Osm;
     
        void test()
        {        
            Osm osm;
            osm.start(); 
     
            std::cout << "> Send OuterEvent()" << std::endl;
            osm.process_event(OuterEvent());
        }
    }
     
    int main()
    {
        test();
        return 0;
    }
    

    你可能在想为什么 用 mpl::vector来定义初始状态init_state。如下代码行与mpl::vector元素为 1 时,所代表的含义一样。

    typedef SubState1 initial_state;
    

    版权声明:自由转载-非商用-非衍生-保持署名创意共享3.0许可证

    相关文章

      网友评论

          本文标题:Boost.Msm 介绍

          本文链接:https://www.haomeiwen.com/subject/jcnnnxtx.html