5

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

UML 2.4 “上层结构”提出了连接伪状态(即第 15.3.8 章)。在 boost 中,有一个fork,但我找不到它的对应连接的任何实现。

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

4

1 回答 1

3

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

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

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

此连接在JoinSM. 每次Join从 到达状态时SubWaiting都会激活状态并递增计数器。如果计数器达到正交区域的数量,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

于 2015-06-19T16:12:12.283 回答