boost msm中的错误处理出错

时间:2012-04-27 10:30:45

标签: c++ boost state-machine

我有一个简单的状态机,它接收3种类型的消息,并根据消息类型发送相应的响应。在正常情况下,按正确顺序收到正确的消息,我的状态机工作正常。


但是在收到意外消息的情况下,会调用no_transition,必须触发error_detected事件,该事件必须由normal_workflow状态处理。但no_transition被称为2次,因为有2个正交区域。但是,只有在error_detected状态的情况下,我才需要触发normal_workflow事件。那么如何确定no_trasition内的当前活动状态? 这是我的代码,

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

一种解决方案是使用传递给no_transition的状态参数。还有其他解决方案吗?因为这样的事情看起来不太好:

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

1 个答案:

答案 0 :(得分:1)

嗯,恕我直言,正交区域的使用是好的。但是,错误处理事件仍然需要由您自己触发。当MSM出错时,no_transition是唯一的功能。所以,我的做法和你一样。