2015-04-20 3 views
5

intendo usare boost.msm con il concetto di composite contenente regioni ortogonali. Voglio sincronizzare tutte le regioni ortogonali all'uscita. In altre parole: lo stato che segue il mio composito deve essere attivato se e solo se tutte le regioni hanno raggiunto il loro ultimo stato.Boost.MSM: Uscita regioni ortogonali tramite un join pseudo stato

UML 2.4 "Superstructure" propone join pseudo stati (cioè capitolo 15.3.8). In boost, c'è una forcella ma non riesco a trovare alcuna implementazione della sua controparte join.

Non c'è nessuno stato pseudo join in boost.msm? Come applicare il concetto di join pseudo stato con boost.msm?

risposta

3

È possibile utilizzare un contatore che aumenterà ogni volta che viene immesso lo stato di join. Quando questo contatore è uguale al numero di regioni ortogonali, verrà attivato lo stato che segue lo stato di join.

Questo potrebbe essere fatto manualmente o in un modo generico. Di seguito ho implementato un modo generico in cui la logica di giunzione è stata aggiunta alla submachine Sub ereditando dal modello JoinSM.

Sub ha 3 regioni ortogonali (che in questo semplice esempio solo costituiti da uno stato ciascuna, cioè Orthogonal1, Orthogonal2 e Orthogonal3). Tutti questi stati ortogonali sono collegati allo stato Join ma non è stato specificato alcun collegamento diretto allo stato Exit dallo stato Join all'interno di Sub.

Questo collegamento è implementato in JoinSM. Ogni volta che viene raggiunto lo stato Join da Sub, lo stato Waiting viene attivato e il contatore viene incrementato. Se il contatore raggiunge il numero di regioni ortogonali, viene attivato l'evento AllJoined e viene attivata la transizione a Exit.

Poiché JoinSM interroga il numero di regioni ortogonali attraverso la dimensione di initial_state, l'aggiunta o la rimozione di aree in Sub si rifletterà automaticamente nella logica di collegamento.

#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()); 
} 

uscita:

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 

esempio dal vivo:http://coliru.stacked-crooked.com/a/6c060d032bc53573