Я намерен использовать boost.msm с концепцией композитный содержащий ортогональные области. Я хочу синхронизировать все ортогональные области при выходе. Другими словами: состояние, следующее за моим соединением, должно быть активировано тогда и только тогда, когда все регионы достигли своего последнего состояния.
UML 2.4 «Надстройка» предлагает присоединиться псевдосостояния (т. е. глава 15.3.8). В бусте есть вилка но я не могу найти какую-либо реализацию его коллеги присоединиться.
Нет ли псевдосоединения в boost.msm? Как бы я применил концепцию псевдо-состояния соединения с boost.msm?
Вы можете использовать счетчик, который будет увеличиваться при каждом входе в состояние соединения. Когда этот счетчик равен числу ортогональных областей, будет активировано состояние, следующее за состоянием соединения.
Это может быть сделано вручную или общим способом.
Ниже я реализовал общий способ добавления логики соединения к автомату. Sub
наследуя от шаблона JoinSM
,
Sub
имеет 3 ортогональных области (которые в этом простом примере состоят только из одного состояния, а именно Orthogonal1
, Orthogonal2
а также Orthogonal3
). Все эти ортогональные состояния связаны с Join
состояние, но нет прямой связи с Exit
государство из Join
состояние указано в пределах Sub
,
Это соединение реализовано в JoinSM
, Каждый раз Join
состояние достигается от Sub
, 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