【问题标题】:Boost MSM switching on current stateBoost MSM 开启当前状态
【发布时间】:2018-07-11 11:58:56
【问题描述】:

我有一个实时循环,我需要根据我所处的状态在每次迭代中完成工作。

我正在使用 Boosts Meta State Machine 库来实现我的状态机。根据我所处的状态调用函数的最佳方式是什么?

假设我有一个超级简单的状态机:

//Events
struct run {};
struct stop {}; 

struct MyStateMachine : public boost::msm::front::state_machine_def<MyStateMachine>
{
    // FSM states
    struct Idle : public boost::msm::front::state<> {};
    struct Running : public boost::msm::front::state<> {};

    typedef Idle initial_state;

    // transition actions
    void do_start(run const&)  { std::cout << "Starting\n"; }
    void do_stop(stop const&)  { std::cout << "Stopping\n"; }

    struct transition_table : boost::mpl::vector<
        //    Start     Event     Next     Action               
      a_row < Idle     , run    , Running, &MyStateMachine::do_start   >,
      a_row < Running  , stop   , Idle   , &MyStateMachine::do_stop    >
    > {};
};

根据我们所处的状态,我可以看到几种工作方式:

1) 开启当前状态

class MyModule : RealTimeModule
{
    void Init() override  { // Called before realtime
        fsm_.start();
    }

    void Step() override {  // Called once each iteration during realtime

        switch(fsm_.current_state()[0])
        {
        case 0:      do_idle();     break;
        case 1:      do_run();      break;
        default:     assert();
        }
    }

    void DoEvent(Event e) override { // Called once per received event

        fsm_.process_event(e);
    }

private: 
    boost::msm::back::state_machine<MyStateMachine> fsm_;
};

这似乎不太好,因为没有直观的方法可以知道case 0空闲case 1正在运行

2) 添加过渡和事件来表示每次迭代

//Events
struct run {}; 
struct stop {};
struct step {}; // !!!NEW EVENT!!!

struct MyStateMachine : public boost::msm::front::state_machine_def<MyStateMachine>
{
    ...
    // transition actions
    void do_start(run const&)  { std::cout << "Starting\n"; }
    void do_stop(stop const&)  { std::cout << "Stopping\n"; }
    void do_idle(step const&)  { std::cout << "Idling  \n";  } //!!!NEW ACTION!!!
    void do_run (step const&)  { std::cout << "Running \n";  } //!!!NEW ACTION!!!

    struct transition_table : boost::mpl::vector<
        //    Start     Event     Next     Action               
      a_row < Idle     , run    , Running, &MyStateMachine::do_start   >,
      a_row < Running  , stop   , Idle   , &MyStateMachine::do_stop    >,
      a_row < Idle     , step   , Idle   , &MyStateMachine::do_idle    >, //!!!NEW TRANSITION!!!
      a_row < Running  , step   , Running, &MyStateMachine::do_step    > //!!!NEW TRANSITION!!!
    > {};
};

class MyModule : RealTimeModule
{
    ...
    void Step() override {
        fsm_.process_event(step); //!!!SIMPLIFIED STEP!!!
    }
    ...
};

这似乎好一点,但我的问题是,如果我想实现 boost::msm::front::state&lt;&gt;::on_entry()on_exit,那么这些函数将在每次迭代时调用,而不是在转换到该状态时调用。


我发现可以使用here 使用的仿函数前端调用带有事件的操作而无需转换。转换表中的行如下所示:

msm::front::Row < Idle, step, msm::front::none, step_idle, msm::front::none >

但是,为了使用它,我需要让我的操作看起来像这样:

struct do_step {
    template <class Event, class Fsm, class SourceState, class TargetState>
    void operator()(Event const&, Fsm&, SourceState&, TargetState&) const {
        std::cout << "Idling" << std::endl;
    }
};

也许这是一种风格问题,但这似乎太冗长而无法成为一个好的解决方案。有没有办法通过使用简单的前端而不是仿函数前端来添加类似msm::front::none 的东西?

【问题讨论】:

    标签: c++ boost state


    【解决方案1】:

    好的,我找到了答案。让我恼火的是,我真的需要阅读未注释的 boost 标头而不是文档或参考资料来弄清楚该怎么做。

    我需要使用不涉及转换的a_irow 结构,而只是调用动作:

    struct transition_table : boost::mpl::vector<
        //    Start     Event     Next     Action               
      a_row < Idle     , run    , Running, &MyStateMachine::do_start   >,
      a_row < Running  , stop   , Idle   , &MyStateMachine::do_stop    >,
     a_irow < Idle     , step   ,          &MyStateMachine::do_idle    >,
     a_irow < Running  , step   ,          &MyStateMachine::do_step    >
    > {};
    

    总而言之,这些是可以添加的行类型:

     a_row<Source, Event, Target, Action       >
      _row<Source, Event, Target               >
       row<Source, Event, Target, Action, Guard>
     g_row<Source, Event, Target,         Guard>
    a_irow<Source, Event,       , Action       >
      irow<Source, Event,         Action, Guard>
    g_irow<Source, Event,                 Guard>
     _irow<Source, Event,                      >  // Forces events to be ignored
    

    与:

    typename Source;
    class    Event;
    typename Target;
    typedef void (Derived::*action)(Event const&) Action;
    typedef bool (Derived::*guard)(Event const&)  Guard;
    

    参考:boost/msm/front/state_machine_def.hpp

    【讨论】: