c++ - Boost::MSM:转换优先级

标签 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;
}

最佳答案

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


嗨,

I try to use boost::MSM to implement a simple state machine for testing purpose. There are several events which have to be processed in the right order, so i defer the other events, which are currently not allowed. I try to defer the events in the transition table, to have one place to look for it, despite having all states to look, what events they defer.

I tried to change the transition rows to change their priorities, but it didnt help. If i unkomment the anonymous transition from live_got_image to live_wait_for_image, it works as expected, but i want to transition automaticly to repeatedly enter the states live_wait_for_image/live_got_image until the ev_stop_live get sent.

恐怕行不通。根据 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,

克里斯托夫

关于c++ - Boost::MSM:转换优先级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29009873/

相关文章:

c++ - 在 C++ 中的错误条件

c++ - boost::msm - 一种获取状态的字符串表示形式(即 getName)的方法?

c++ - Boost MSM 库给出错误

Boost MSM,尽管 boost::any 被用作事件,但转换不会发生

c# - C# 中匿名 lambda 函数的 C++ 捕获子句等效项

c++ unzip 返回无法创建提取目录

c++ - '随机' : identifier not found error

.net - 视觉 C++.net : Disappearing project

c++ - 如何动态创建状态机

c++ - Boost msm 子子状态机