Boost.MSM: esci da regioni ortogonali tramite uno stato pseudo join

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