Intendo utilizzare boost.msm con il concetto di composito contenente regioni ortogonali . Voglio sincronizzare tutte le regioni ortogonali all’uscita. In altre parole: lo stato che segue il mio composito deve essere triggersto se e solo se tutte le regioni hanno raggiunto il loro ultimo stato.
UML 2.4 “Superstructure” propone join pseudo stati (es. Capitolo 15.3.8). In boost, c’è un fork ma non riesco a trovare alcuna implementazione della sua controparte join.
Non c’è uno stato pseudo join in boost.msm? Come applicare il concetto di join pseudo stato con boost.msm?
È ansible utilizzare un contatore che aumenterà ogni volta che viene inserito lo stato di join. Quando questo contatore è uguale al numero di regioni ortogonali, verrà triggersto lo stato che segue lo stato di join.
Questo potrebbe essere fatto manualmente o in modo generico. Di seguito ho implementato un modo generico in cui la logica di giunzione viene aggiunta al sottomano Sub
ereditando dal modello JoinSM
.
Sub
ha 3 regioni ortogonali (che in questo semplice esempio sono costituite da uno stato ciascuna, ovvero Orthogonal1
, Orthogonal2
e Orthogonal3
). Tutti questi stati ortogonali sono collegati allo stato Join
ma nessuna connessione diretta allo stato Exit
dallo stato Join
è specificata in Sub
.
Questa connessione è implementata in JoinSM
. Ogni volta che lo stato Join
viene raggiunto da Sub
, lo stato di Waiting
viene triggersto e il contatore viene incrementato. Se il contatore raggiunge il numero di regioni ortogonali, viene triggersto l’evento AllJoined
e viene triggersta la transizione a Exit
.
Poiché JoinSM
interroga il numero di regioni ortogonali attraverso la dimensione di initial_state
, l’aggiunta o la rimozione di regioni in Sub
si rifletterà automaticamente nella logica di unione.
#include #include #include #include template std::string demangle() { const char* name = typeid(T).name(); int status = -1; std::unique_ptr res { abi::__cxa_demangle(name, NULL, NULL, &status), std::free }; return (status==0) ? res.get() : name ; } #include #include #include #include #include using namespace boost::msm; using namespace boost::msm::front; template struct BaseState : public boost::msm::front::state<> { template void on_entry(Event const&,FSM& ) { std::cout << "on_entry: " << demangle() << std::endl; } template void on_exit(Event const&,FSM& ) { std::cout << "on_exit: " << demangle() << std::endl; } }; // EVENTS struct EnterOrthogonal {}; struct Orthogonal1Finished{}; struct Orthogonal2Finished{}; struct Orthogonal3Finished{}; struct SubSM_ : state_machine_def { struct Started : BaseState{}; struct Exit : exit_pseudo_state {}; struct Orthogonal1 : BaseState{}; struct Orthogonal2 : BaseState{}; struct Orthogonal3 : BaseState{}; struct Join : BaseState{}; typedef boost::mpl::vector initial_state; struct transition_table : boost::mpl::vector< Row, Row, Row > {}; }; template struct JoinSM : SM { struct AllJoined{}; constexpr static int num_regions = boost::mpl::size ::value; int count; template void on_entry(Event const& ,FSM&) { // reset count count = 0; } struct Waiting : BaseState { template void on_entry(const Event& e,FSM& f) { BaseState::on_entry(e,f); f.count++; if (f.count == FSM::num_regions) { f.process_event(AllJoined()); } } }; typedef boost::mpl::vector< Row, Row > 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>; struct MainSM_ : state_machine_def { struct Started : BaseState{}; struct AfterJoin : BaseState{}; using initial_state = boost::mpl::vector; struct transition_table : boost::mpl::vector< Row, Row, none, AfterJoin, none, none> > {}; }; struct MainSM_; using Main = back::state_machine; int main() { Main main; main.start(); main.process_event(EnterOrthogonal()); main.process_event(Orthogonal3Finished()); main.process_event(Orthogonal1Finished()); main.process_event(Orthogonal2Finished()); }
Produzione:
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::Waiting on_exit: SubSM_::Orthogonal1 on_entry: SubSM_::Join on_exit: SubSM_::Join on_entry: JoinSM::Waiting on_exit: SubSM_::Orthogonal2 on_entry: SubSM_::Join on_exit: SubSM_::Join on_entry: JoinSM::Waiting on_exit: JoinSM::Waiting on_exit: JoinSM::Waiting on_exit: JoinSM::Waiting on_entry: MainSM_::AfterJoin
Esempio dal vivo: http://coliru.stacked-crooked.com/a/6c060d032bc53573