Boost.MSM:通过联接伪状态退出正交区域 [英] Boost.MSM: Exit orthogonal regions via a join pseudo state
问题描述
I intend to use boost.msm with the concept of composite containing orthogonal regions. I want to synchronize all orthogonal regions upon exit. In other words: the state following my composite shall be activated if and only if all regions have reached their last state.
UML 2.4上层建筑" 建议 加入 伪状态(即第15.3.8节).在boost中,有一个 fork ,但是我找不到对应的join的任何实现.
UML 2.4 "Superstructure" proposes join pseudo states (i.e. chapter 15.3.8). In boost, there is a fork but I cannot find any implementation of its counterpart join.
boost.msm中是否没有连接伪状态?我将如何在boost.msm中应用加入伪状态的概念?
推荐答案
您可以使用一个计数器,该计数器在每次进入连接状态时都会增加.当此计数器等于正交区域数时,将激活联接状态之后的状态.
You could use a counter which will increment each time the join state is entered. When this counter equals the number of orthogonal regions, the state following the join state will be activated.
这可以手动完成,也可以通过一般方式完成.
下面,我实现了一种通用方法,其中通过从模板JoinSM
继承,将联接逻辑添加到子计算机Sub
中.
This could be done manually or in a generic way.
Below I implemented a generic way where the joining logic is added to the submachine Sub
by inheriting from the template JoinSM
.
Sub
具有3个正交区域(在此简单示例中,每个区域仅包含一个状态,即Orthogonal1
,Orthogonal2
和Orthogonal3
).所有这些正交状态都连接到Join
状态,但是在Sub
中未指定从Join
状态直接连接到Exit
状态.
Sub
has 3 orthogonal regions (which in this simple example just consist of one state each, namely Orthogonal1
, Orthogonal2
and Orthogonal3
). All of these orthogonal states are connected to the Join
state but no direct connection to the Exit
state from the Join
state is specified within Sub
.
此连接在JoinSM
中实现.每次从Sub
进入Join
状态时,都会激活Waiting
状态并使计数器递增.如果计数器达到正交区域数,则触发事件AllJoined
并激活到Exit
的过渡.
This connection is implemented in JoinSM
. Every time the Join
state is reached from Sub
, the Waiting
state is activated and the counter is incremented. If the counter reaches the number of orthogonal regions, the Event AllJoined
is fired and the transition to Exit
is activated.
由于JoinSM
通过initial_state
的大小查询正交区域的数量,因此在Sub
中添加或删除区域将自动反映在连接逻辑中.
Since JoinSM
queries the number of orthogonal regions through the size of initial_state
, adding or removing regions in Sub
will automatically be reflected in the joining logic.
#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
这篇关于Boost.MSM:通过联接伪状态退出正交区域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!