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

初始状态转换的动作

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

在如下代码片段中,此初始状态类型定义仅仅表明状态机从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 的转换。

明确地指定的事件句柄

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;
    }
}

自转变和内部转变


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 >
        > {};

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

为了实现内部转换有两种不同方式。一种是在状态机中利用正常转变表并设置其 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

连接点伪状态

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

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 >
        > {};

选择伪状态

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

这两个图表很相似。其唯一的差别在于一个用连接伪状态,另一个用选择伪状态。先来看图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

延时事件

TODO.

参考链接:
https://www.jianshu.com/p/6748aa7c117b

posted @ 2020-05-13 22:09  多弗朗强哥  阅读(474)  评论(0编辑  收藏  举报