我有一个实时循环,我需要根据我所处的状态进行每次迭代的工作。
我正在使用 Boosts Meta State Machine 库来实现我的状态机。根据我所处的状态调用函数的最佳方法是什么?
假设我有一个 super 简单的状态机:
//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<>::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
的内容通过使用简单的前端而不是仿函数前端?
最佳答案
好的,我找到了答案。让我很恼火的是,我真的需要阅读未注释的 boost header 而不是文档或引用资料来弄清楚该怎么做。
我需要使用 a_irow
不涉及转换的结构,而只是调用 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_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
关于c++ - Boost MSM 开启当前状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51284931/