2

我有一个简单的状态机,它接收 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());
    }
}
4

1 回答 1

1

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

于 2012-05-14T05:43:55.920 回答