2012-04-27 3 views
2

J'ai une machine à états simple, elle reçoit 3 types de messages et, en fonction du type de message, elle envoie une réponse correspondante. Dans les situations normales où les messages corrects reçus dans le bon ordre ma machine d'état fonctionne parfaitement.Erreur lors de la gestion des erreurs dans boost msm


Mais dans les cas où un message inattendu est reçu, no_transition est appelée, qui doit tirer événement error_detected, qui doit être gérée par l'Etat normal_workflow. Mais no_transition est appelé 2 fois, car il y a 2 régions orthogonales. Mais j'ai besoin de feu error_detected événement seulement dans le cas de l'état normal_workflow. Alors, comment déterminer l'état actif actuel dans no_trasition? Voici mon code,

#include <iostream> 

#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/front/euml/common.hpp> 

#include <boost/msm/front/euml/operator.hpp> 
#include <boost/msm/front/euml/state_grammar.hpp> 

namespace msm = boost::msm; 
namespace mpl = boost::mpl; 

using namespace msm::front; 
using namespace msm::front::euml; 

namespace 
{ 
    // events 
    // 
    struct received_type_1_msg { received_type_1_msg(){ std::cout << "received_type_1_msg" << std::endl; } }; 

    struct received_type_2_msg { received_type_2_msg(){ std::cout << "received_type_2_msg" << std::endl; } }; 

    struct received_type_3_msg { received_type_3_msg(){ std::cout << "received_type_3_msg" << std::endl; } }; 

    struct err_detected { err_detected(){ std::cout << "err_detected" << std::endl; } }; 

    // front end 
    // 
    struct test_sm_ : public msm::front::state_machine_def<test_sm_> 
    { 
     // states 
     // 
     struct idle : public msm::front::state<> 
     { 
      template <class event,class fsm> 
      void on_entry(event const& evt,fsm& sm) 
      { 
       std::cout << "idle" << std::endl; 
      } 
     }; 

     struct wait_type_2_msg : public msm::front::state<> 
     { 
      template <class event,class fsm> 
      void on_entry(event const& evt,fsm& sm) 
      { 
       std::cout << "wait_type_1_msg"<< std::endl; 
      } 
     }; 

     struct wait_type_3_msg : public msm::front::state<> 
     { 
      template <class event,class fsm> 
      void on_entry(event const& evt,fsm& sm) 
      { 
       std::cout << "wait_type_3_msg"<< std::endl; 
      } 
     }; 

     struct normal_workflow : public msm::front::state<> 
     { 
      template <class event,class fsm> 
      void on_entry(event const& evt,fsm& sm) 
      { 
       std::cout << "normal_workflow"<< std::endl; 
      } 
     };  

     // initial state 
     // 
     typedef mpl::vector2<idle, normal_workflow> initial_state; 

     // transition actions 
     // 
     struct send_type_1_rsp 
     { 
      template<class event, class fsm, class src_state, class dst_state> 
      void operator()(event const& evt, fsm&, src_state&, dst_state&) 
      { 
       std::cout << "send_type_1_rsp"<< std::endl; 
      } 
     }; 

     struct send_type_2_rsp 
     { 
      template<class event, class fsm, class src_state, class dst_state> 
      void operator()(event const& evt, fsm&, src_state&, dst_state&) 
      { 
       std::cout << "send_type_2_rsp"<< std::endl; 
      } 
     }; 

     struct send_type_3_rsp 
     { 
      template<class event, class fsm, class src_state, class dst_state> 
      void operator()(event const& evt, fsm&, src_state&, dst_state&) 
      { 
       std::cout << "send_type_3_rsp"<< std::endl; 
      } 
     }; 

     struct send_error_rsp 
     { 
      template<class event, class fsm, class src_state, class dst_state> 
      void operator()(event const& evt, fsm&, src_state&, dst_state&) 
      { 
       std::cout << "send_error_rsp"<< std::endl; 
      } 
     }; 

     struct transition_table : mpl::vector< 

      //  Start      Event       Next      Action       Guard 
      // +---------------------------+-------------------------------+---------------------------+------------------------------+--------+ 
      Row < idle      , received_type_1_msg   , wait_type_2_msg   , send_type_1_rsp    , none >, 
      Row < wait_type_2_msg   , received_type_2_msg   , wait_type_3_msg   , send_type_2_rsp    , none >, 
      Row < wait_type_3_msg   , received_type_3_msg   , idle      , send_type_3_rsp    , none >, 
      // +---------------------------+-------------------------------+---------------------------+------------------------------+--------+ 
      Row < normal_workflow   , err_detected     , idle      , send_error_rsp    , none > 
      // +---------------------------+-------------------------------+---------------------------+------------------------------+--------+ 
     >{}; 

     // no transition 
     // 
     template <class fsm,class event> 
     void no_transition(event const& e, fsm& sm,int state) 
     { 
      std::cout << "no transition" << std::endl; 
      //sm.process_event(err_detected()); 
     } 
    }; 

    typedef msm::back::state_machine<test_sm_> test_sm; 
} 

int main(int argc, char** argv) 
{ 
    test_sm sm; 
    sm.start(); 

    sm.process_event(received_type_1_msg()); 
    sm.process_event(received_type_2_msg()); 

    // wrong message received 
    // 
    sm.process_event(received_type_2_msg()); 

    return 0; 
} 

Une solution est par l'intermédiaire en utilisant l'argument de l'Etat qui est passé à no_transition. N 'y a-t-il pas une autre solution? Parce que quelque chose comme ça ne semble pas bon:

template <class fsm,class event> 
void no_transition(event const& e, fsm& sm,int state) 
{ 
    // without this condition err_detected event will fired twise, because sm have 2 regions 
    // 
    if(state == 3) 
    { 
     // call this event only in NORMAL_WORKFLOW state, because it handled within this state 
     // 
     sm.process_event(err_detected()); 
    } 
} 

Répondre

1

Eh bien, à mon humble avis, l'utilisation de régions orthogonales est bon. Cependant, l'événement de gestion des erreurs doit toujours être déclenché par vous-même. no_transition est la seule fonction lorsque MSM se trompe. donc, je le fais de la même manière que vous l'avez fait.