Boost :: MSM:过渡优先级

时间:2015-03-12 12:32:39

标签: c++ boost-msm

我尝试使用boost :: MSM来实现一个简单的状态机以进行测试。有几个事件必须按正确的顺序处理,所以我推迟了其他事件,这些事件目前是不允许的。我尝试推迟转换表中的事件,有一个地方可以查找它,尽管要查看所有状态,他们推迟了什么事件。

我尝试更改转换行以更改其优先级,但它没有帮助。如果我取消从live_got_image到live_wait_for_image的匿名转换,它会按预期工作,但我想自动转换为重复进入状态live_wait_for_image / live_got_image,直到ev_stop_live被发送。

我期待以下输出:

entering: fsm_master
entering: not_ready
no transition from state 0 on event struct `anonymous namespace'::ev_stop_live
leaving: not_ready
starting: live_wait_for_image
leaving: live_wait_for_image
starting: live_got_image
leaving: live_got_image
entering: not_ready

但实际上我得到以下输出:

entering: fsm_master
entering: not_ready
no transition from state 0 on event struct `anonymous namespace'::ev_stop_live
leaving: not_ready
starting: live_wait_for_image
leaving: live_wait_for_image
starting: live_got_image
leaving: live_got_image
starting: live_wait_for_image   

我使用boost 1.57.0和MSVC-2013(VS-12)。

有人能给我一个有用的提示吗?

乔治

以下是代码:

#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>

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

namespace 
{
    using namespace boost::msm::front;

    // events
    struct ev_start_stop {};
    struct ev_start_live {};
    struct ev_stop_live {};
    struct ev_learn {};
    struct ev_load {};

    struct ev_got_image { int payload;  };

    // front end: define the FSM structure
    struct fsm_master_ : public msm::front::state_machine_def<fsm_master_> {
        typedef int activate_deferred_events;

        template <class Event, class FSM>
        void on_entry(Event const&, FSM&)
        {
            std::cout << "entering: fsm_master" << std::endl;
        }
        template <class Event, class FSM>
        void on_exit(Event const&, FSM&)
        {
            std::cout << "leaving: fsm_master" << std::endl;
        }

        // the fsm states which are not sub state machines
        struct not_ready : public msm::front::state<> {
            template <class Event, class FSM>
            void on_entry(Event const&, FSM&) { std::cout << "entering: not_ready" << std::endl; }
            template <class Event, class FSM>
            void on_exit(Event const&, FSM&) { std::cout << "leaving: not_ready" << std::endl; }
        };

        // The list of FSM states
        struct live_wait_for_image : public msm::front::state<>
        {
            template <class Event, class FSM>
            void on_entry(Event const&, FSM&) { std::cout << "starting: live_wait_for_image" << std::endl; }
            template <class Event, class FSM>
            void on_exit(Event const&, FSM&) { std::cout << "leaving: live_wait_for_image" << std::endl; }
        };

        struct live_got_image : public msm::front::state<>
        {
            // here we got the image and we can check, if we need to react on an external event
            // otherwise transit to wait_for_image and fetch the next image
            template <class Event, class FSM>
            void on_entry(Event const&, FSM&) { std::cout << "starting: live_got_image" << std::endl; }
            template <class Event, class FSM>
            void on_exit(Event const&, FSM&) { std::cout << "leaving: live_got_image" << std::endl; }
        };

        // ---------------------------------------------------
        // initial state: fsm_master_
        typedef not_ready   initial_state;

        typedef fsm_master_ l;
        struct transition_table : mpl::vector<
            //      Start           Event            Next             Action              Guard
            //    +---------------------+----------------+-------------------+-------------------+----------------+
            _row < not_ready,           ev_start_live,   live_wait_for_image                                       >,

            _row < live_wait_for_image, ev_got_image,    live_got_image                                            >,
             Row < live_wait_for_image, ev_stop_live,    none                , Defer             , none            >,

            _row < live_got_image,      none,            live_wait_for_image                                       >,
            _row < live_got_image,      ev_stop_live,    not_ready                                                 >
            //    +---------------------+----------------+-------------------+-------------------+----------------+
        > {};

        // Replaces the default no-transition response.
        template <class FSM, class Event>
        void no_transition(Event const& e, FSM&, int state)
        {
            std::cout << "no transition from state " << state
                << " on event " << typeid(e).name() << std::endl;
        }

    };

    // back-end: fsm_master
    typedef msm::back::state_machine<fsm_master_> fsm_master;
}

void test() {
    fsm_master s;
    s.start();

    s.process_event(ev_stop_live()); // this gets no transitioned

    s.process_event(ev_start_live()); // this one enters live
    s.process_event(ev_stop_live()); // this gets defered   
    s.process_event(ev_got_image()); // this one enters got_image and the stop live should get processed. 

    // now we should be in not ready again, but we are still in live_wait_for_image

}
int main()
{
    test();
    return 0;
}

1 个答案:

答案 0 :(得分:1)

我从Christophe的邮件列表中得到了以下答案:


您好,

  

我尝试使用boost :: MSM来实现一个简单的状态机进行测试   目的。有几个事件必须在右边处理   订单,所以我推迟了目前不允许的其他事件。我试试   推迟转换表中的事件,有一个地方可以查找   尽管有所有州看,但他们推迟了什么事。

     

我尝试更改转换行以更改其优先级,但它   没有帮助。如果我解开从live_got_image到的匿名过渡   live_wait_for_image,它按预期工作,但我想转换   自动重复进入状态   live_wait_for_image / live_got_image,直到ev_stop_live被发送。

我担心它不起作用。根据MSM试图遵循的UML标准,匿名转换具有比延迟事件更高的优先级。如果队列中有延迟事件,您可以在匿名转换中使用保护来禁用它,例如:

struct OnlyIfNoDeferred
{
    template<class Event, class Fsm, class SourceState, class TargetState>
    bool operator()(Event const &, Fsm & aFsm, SourceState &, TargetState &)
    {
        return aFsm.get_deferred_queue().empty();
    }
};

当我们谈论匿名过渡时,我会反复阅读,但请注意不要添加另一个匿名过渡,否则你可能会进入无限循环的匿名过渡。

HTH,

克里斯托弗