【问题标题】:Boost.MSM: Exit orthogonal regions via a join pseudo stateBoost.MSM:通过连接伪状态退出正交区域
【发布时间】:2015-06-27 02:58:44
【问题描述】:

我打算将 boost.msm 与包含 正交区域composite 概念一起使用。我想在退出时同步所有正交区域。换句话说:当且仅当所有区域都达到其最后一个状态时,我的复合之后的状态才会被激活。

UML 2.4 "Superstructure" 提出 join 伪状态(即第 15.3.8 章)。在 boost 中,有一个 fork,但我找不到其对应连接的任何实现。

boost.msm中没有join伪状态吗?我如何将加入伪状态的概念与 boost.msm 一起应用?

【问题讨论】:

    标签: c++ boost uml boost-msm


    【解决方案1】:

    您可以使用每次进入连接状态时都会递增的计数器。当此计数器等于正交区域的数量时,将激活加入状态之后的状态。

    这可以手动或以通用方式完成。 下面我实现了一种通用方式,通过从模板JoinSM 继承将连接逻辑添加到子机Sub

    Sub 有 3 个正交区域(在这个简单的示例中,每个区域仅包含一个状态,即 Orthogonal1Orthogonal2Orthogonal3)。所有这些正交状态都连接到Join 状态,但在Sub 中没有指定从Join 状态直接连接到Exit 状态。

    此连接在JoinSM 中实现。每次从Sub 到达Join 状态时,都会激活Waiting 状态并且计数器递增。如果计数器达到正交区域的数量,则触发事件AllJoined 并激活到Exit 的转换。

    由于JoinSM通过initial_state的大小查询正交区域的数量,在Sub中添加或删除区域将自动反映在连接逻辑中。

    #include <iostream>
    #include <cstdlib>
    #include <memory>
    #include <cxxabi.h>
    
    template <class T>
    std::string demangle()
    {
        const char* name = typeid(T).name();
        int status = -1; 
        std::unique_ptr<char, void(*)(void*)> res {
            abi::__cxa_demangle(name, NULL, NULL, &status),
            std::free
        };
        return (status==0) ? res.get() : name ;
    }
    
    
    #include <boost/msm/back/state_machine.hpp>
    #include <boost/msm/front/state_machine_def.hpp>
    #include <boost/msm/front/functor_row.hpp>
    #include <boost/msm/back/metafunctions.hpp>
    #include <boost/mpl/assert.hpp>
    
    using namespace boost::msm;
    using namespace boost::msm::front;
    
    
    template <typename State>
    struct BaseState : public boost::msm::front::state<>
    {
        template <class Event,class FSM> void on_entry(Event const&,FSM& )
        {
            std::cout << "on_entry: " << demangle<State>()  << std::endl;
        }
        template <class Event,class FSM> void on_exit(Event const&,FSM& ) 
        {
            std::cout << "on_exit: " << demangle<State>() << std::endl;
        }
    };
    
    
    // EVENTS
    struct EnterOrthogonal {};
    
    struct Orthogonal1Finished{};
    struct Orthogonal2Finished{};
    struct Orthogonal3Finished{};
    
    
    
    struct SubSM_ : state_machine_def<SubSM_>
    {
        struct Started : BaseState<Started>{};
        struct Exit : exit_pseudo_state<none> {};
    
        struct Orthogonal1 : BaseState<Orthogonal1>{};
        struct Orthogonal2 : BaseState<Orthogonal2>{};
        struct Orthogonal3 : BaseState<Orthogonal3>{};
    
        struct Join : BaseState<Join>{};
    
        typedef boost::mpl::vector<Orthogonal1, Orthogonal2, Orthogonal3> initial_state;
        struct transition_table : boost::mpl::vector<
         Row<Orthogonal1, Orthogonal1Finished, Join, none, none>,
         Row<Orthogonal2, Orthogonal2Finished, Join, none, none>,
         Row<Orthogonal3, Orthogonal3Finished, Join, none, none>
         > {};
    };
    
    
    template <typename SM, typename JoinState = typename SM::Join, typename ExitState = typename SM::Exit>
    struct JoinSM  : SM
    {
        struct AllJoined{};
    
        constexpr static int num_regions = boost::mpl::size<typename SM::initial_state>::value;
        int count;
    
        template <class Event,class FSM>
        void on_entry(Event const& ,FSM&) 
        {
            // reset count
            count = 0;
        }
    
        struct Waiting : BaseState<Waiting>
        {
            template <class Event,class FSM>
            void on_entry(const Event& e,FSM& f)
            {
                BaseState<Waiting>::on_entry(e,f);
                f.count++; 
                if (f.count == FSM::num_regions)
                {
                    f.process_event(AllJoined()); 
                } 
            }
        };
    
        typedef boost::mpl::vector<
            Row<JoinState, none, Waiting, none, none>,
            Row<Waiting, AllJoined, ExitState, none, none>
        > additional_transition_table;
    
        typedef boost::mpl::joint_view<
            typename SM::transition_table,
            additional_transition_table
        > transition_table;
    };
    
    // inherit from JoinSM to add the joining logic
    using Sub = back::state_machine<JoinSM<SubSM_>>;
    
    struct MainSM_ : state_machine_def<MainSM_>
    {
        struct Started : BaseState<Started>{};
        struct AfterJoin : BaseState<AfterJoin>{};
        using initial_state = boost::mpl::vector<Started>;
        struct transition_table : boost::mpl::vector<
            Row<Started, EnterOrthogonal, Sub, none, none>,
            Row<Sub::exit_pt<SubSM_::Exit>, none, AfterJoin, none, none>
        > {};
    };
    
    struct MainSM_;
    using Main = back::state_machine<MainSM_>;    
    
    
    int main()
    {
    
        Main main;
        main.start();
        main.process_event(EnterOrthogonal());
        main.process_event(Orthogonal3Finished());
        main.process_event(Orthogonal1Finished());
        main.process_event(Orthogonal2Finished());
    }
    

    输出:

    on_entry: MainSM_::Started
    on_exit: MainSM_::Started
    on_entry: SubSM_::Orthogonal1
    on_entry: SubSM_::Orthogonal2
    on_entry: SubSM_::Orthogonal3
    on_exit: SubSM_::Orthogonal3
    on_entry: SubSM_::Join
    on_exit: SubSM_::Join
    on_entry: JoinSM<SubSM_, SubSM_::Join, SubSM_::Exit>::Waiting
    on_exit: SubSM_::Orthogonal1
    on_entry: SubSM_::Join
    on_exit: SubSM_::Join
    on_entry: JoinSM<SubSM_, SubSM_::Join, SubSM_::Exit>::Waiting
    on_exit: SubSM_::Orthogonal2
    on_entry: SubSM_::Join
    on_exit: SubSM_::Join
    on_entry: JoinSM<SubSM_, SubSM_::Join, SubSM_::Exit>::Waiting
    on_exit: JoinSM<SubSM_, SubSM_::Join, SubSM_::Exit>::Waiting
    on_exit: JoinSM<SubSM_, SubSM_::Join, SubSM_::Exit>::Waiting
    on_exit: JoinSM<SubSM_, SubSM_::Join, SubSM_::Exit>::Waiting
    on_entry: MainSM_::AfterJoin
    

    现场示例: http://coliru.stacked-crooked.com/a/6c060d032bc53573

    【讨论】:

      猜你喜欢
      • 2023-03-15
      • 2015-04-21
      • 2013-08-21
      • 2012-03-07
      • 2021-06-21
      • 1970-01-01
      • 1970-01-01
      • 2013-04-23
      • 2014-03-17
      相关资源
      最近更新 更多