0、什么是有限状态机
有限状态机(FSM)是一种数学模型,用于表示系统中不同状态之间的转换。FSM 由以下几部分组成:
- 状态(State):表示系统的不同阶段。
- 事件(Event):触发状态转换的条件。
- 转换(Transition):在特定事件发生时,系统从一个状态转移到另一个状态。
- 动作(Action):状态转换时执行的操作,通常在进入某个状态或从某个状态退出时发生。
在很多嵌入式系统、游戏开发以及应用程序控制中,FSM 是一种非常实用的设计模式。它能够帮助我们清晰地设计出状态之间的转换和行为逻辑。
1、tinyFSM源码分析
TinyFSM 是一个极其轻量级的库。它专注于实现有限状态机的核心功能,并且避免了不必要的复杂性。因为代码行数比较少,因此直接将源码贴到下面,并将本人的理解以注释的形式添加到代码中,直接看代码
namespace tinyfsm
{// --------------------------------------------------------------------------struct Event { };// --------------------------------------------------------------------------#ifdef TINYFSM_NOSTDLIB// remove dependency on standard library (silent fail!).// useful in conjunction with -nostdlib option, e.g. if your compiler// does not provide a standard library.// NOTE: this silently disables all static_assert() calls below!template<typename F, typename S>struct is_same_fsm { static constexpr bool value = true; };
#else// check if both fsm and state class share same fsmtypetemplate<typename F, typename S>// std::is_same的作用是判断两个类型是不是一样的,下面语句的typename的主要作用是告诉编译器后面是一个类型struct is_same_fsm : std::is_same< typename F::fsmtype, typename S::fsmtype > { };
#endiftemplate<typename S>struct _state_instance{using value_type = S;using type = _state_instance<S>;static S value;};template<typename S>// typename 告诉编译器后面是一个类型,这里实际是给静态变量分配空间typename _state_instance<S>::value_type _state_instance<S>::value;// --------------------------------------------------------------------------template<typename F>class Fsm{public:using fsmtype = Fsm<F>;using state_ptr_t = F *;static state_ptr_t current_state_ptr;// public, leaving ability to access state instance (e.g. on reset)template<typename S>// 获取定义的状态S的值static constexpr S & state(void) {static_assert(is_same_fsm<F, S>::value, "accessing state of different state machine");return _state_instance<S>::value;}template<typename S>// 检测状态机是不是在状态Sstatic constexpr bool is_in_state(void) {static_assert(is_same_fsm<F, S>::value, "accessing state of different state machine");return current_state_ptr == &_state_instance<S>::value;}/// state machine functionspublic:// explicitely specialized in FSM_INITIAL_STATE macrostatic void set_initial_state();static void reset() { };static void enter() {current_state_ptr->entry();}static void start() {set_initial_state();enter();}template<typename E>static void dispatch(E const & event) {current_state_ptr->react(event);}/// state transition functionsprotected:// S 是要进入的状态template<typename S>void transit(void) {static_assert(is_same_fsm<F, S>::value, "transit to different state machine");current_state_ptr->exit();current_state_ptr = &_state_instance<S>::value;current_state_ptr->entry();}// 切换到 S 状态之前执行动作action_functiontemplate<typename S, typename ActionFunction>void transit(ActionFunction action_function) {static_assert(is_same_fsm<F, S>::value, "transit to different state machine");current_state_ptr->exit();// NOTE: do not send events in action_function definisions.action_function();current_state_ptr = &_state_instance<S>::value;current_state_ptr->entry();}// 满足条件condition_function时,切换到S,并执行action_function动作template<typename S, typename ActionFunction, typename ConditionFunction>void transit(ActionFunction action_function, ConditionFunction condition_function) {if(condition_function()) {transit<S>(action_function);}}};template<typename F>typename Fsm<F>::state_ptr_t Fsm<F>::current_state_ptr;// --------------------------------------------------------------------------// 这里是定义了FsmList,有一个特化版本template<> struct FsmList<>// 泛化版本,利用了模板递归技术,定义了各种递归方法,出口是特化版本template<typename... FF>struct FsmList;template<> struct FsmList<> {static void set_initial_state() { }static void reset() { }static void enter() { }template<typename E>static void dispatch(E const &) { }};template<typename F, typename... FF>struct FsmList<F, FF...>{using fsmtype = Fsm<F>;static void set_initial_state() {fsmtype::set_initial_state();FsmList<FF...>::set_initial_state();}static void reset() {F::reset();FsmList<FF...>::reset();}static void enter() {fsmtype::enter();FsmList<FF...>::enter();}static void start() {set_initial_state();enter();}template<typename E>static void dispatch(E const & event) {fsmtype::template dispatch<E>(event);FsmList<FF...>::template dispatch<E>(event);}};// --------------------------------------------------------------------------// 状态管理,技术和上面的技术一样template<typename... SS> struct StateList;template<> struct StateList<> {static void reset() { }};template<typename S, typename... SS>struct StateList<S, SS...>{static void reset() {_state_instance<S>::value = S();StateList<SS...>::reset();}};// --------------------------------------------------------------------------template<typename F>struct MooreMachine : tinyfsm::Fsm<F>{virtual void entry(void) { }; /* entry actions in some states */void exit(void) { }; /* no exit actions */};template<typename F>struct MealyMachine : tinyfsm::Fsm<F>{// input actions are modeled in react():// - conditional dependent of event type or payload// - transit<>(ActionFunction)void entry(void) { }; /* no entry actions */void exit(void) { }; /* no exit actions */};} /* namespace tinyfsm */// 这个宏的作用是设置有限状态机的初始状态
#define FSM_INITIAL_STATE(_FSM, _STATE) \
namespace tinyfsm { \template<> void Fsm< _FSM >::set_initial_state(void) { \current_state_ptr = &_state_instance< _STATE >::value; \} \
}#endif /* TINYFSM_HPP_INCLUDED */
2、使用实例
下面是tinyFsm库中的电梯的使用示例,代码不是很难理解,只添加了少量注释:
// moctor.hpp
struct FloorEvent : tinyfsm::Event
{int floor;
};
// 定义了3个事件
struct Call : FloorEvent { };
struct FloorSensor : FloorEvent { };
struct Alarm : tinyfsm::Event { };// ----------------------------------------------------------------------------
// Elevator (FSM base class) declaration
//class Elevator
: public tinyfsm::Fsm<Elevator>
{/* NOTE: react(), entry() and exit() functions need to be accessible* from tinyfsm::Fsm class. You might as well declare friendship to* tinyfsm::Fsm, and make these functions private:** friend class Fsm;*/
public:/* default reaction for unhandled events */void react(tinyfsm::Event const &) { };// 该状态机发生了上面的事件时,该如何反应virtual void react(Call const &);virtual void react(FloorSensor const &);void react(Alarm const &);// 留给具体的状态去实现virtual void entry(void) { }; /* entry actions in some states */void exit(void) { }; /* no exit actions at all */protected:static constexpr int initial_floor = 0;static int current_floor;static int dest_floor;
};
// -------------------------------
// moctor.cpp
// -------------------------------
class Stopped
: public Motor
{void entry() override {std::cout << "Motor: stopped" << std::endl;direction = 0;};
};class Up
: public Motor
{void entry() override {std::cout << "Motor: moving up" << std::endl;direction = 1;};
};class Down
: public Motor
{void entry() override {std::cout << "Motor: moving down" << std::endl;direction = -1;};
};// ----------------------------------------------------------------------------
// Base State: default implementations
//void Motor::react(MotorStop const &) {transit<Stopped>();
}void Motor::react(MotorUp const &) {transit<Up>();
}void Motor::react(MotorDown const &) {transit<Down>();
}int Motor::direction{0};
// -------------------------------
// elevator.hpp
// -------------------------------
struct FloorEvent : tinyfsm::Event
{int floor;
};
// 定义3个事件
struct Call : FloorEvent { };
struct FloorSensor : FloorEvent { };
struct Alarm : tinyfsm::Event { };// ----------------------------------------------------------------------------
// Elevator (FSM base class) declaration
//class Elevator
: public tinyfsm::Fsm<Elevator>
{/* NOTE: react(), entry() and exit() functions need to be accessible* from tinyfsm::Fsm class. You might as well declare friendship to* tinyfsm::Fsm, and make these functions private:** friend class Fsm;*/
public:/* default reaction for unhandled events */void react(tinyfsm::Event const &) { };// 状态机处理对应的动作,需函数留给子类实现virtual void react(Call const &);virtual void react(FloorSensor const &);void react(Alarm const &);virtual void entry(void) { }; /* entry actions in some states */void exit(void) { }; /* no exit actions at all */protected:static constexpr int initial_floor = 0;static int current_floor;static int dest_floor;
};
// -------------------------------
// elevator.cpp
// -------------------------------
// State: Panic
//class Panic
: public Elevator
{void entry() override {// 发送时间给Motor状态机send_event(MotorStop());}
};// ----------------------------------------------------------------------------
// State: Moving
//class Moving
: public Elevator
{void react(FloorSensor const & e) override {int floor_expected = current_floor + Motor::getDirection();if(floor_expected != e.floor){std::cout << "Floor sensor defect (expected " << floor_expected << ", got " << e.floor << ")" << std::endl;transit<Panic>(CallMaintenance);}else{std::cout << "Reached floor " << e.floor << std::endl;current_floor = e.floor;if(e.floor == dest_floor)transit<Idle>();}};
};// ----------------------------------------------------------------------------
// State: Idle
//class Idle
: public Elevator
{void entry() override {send_event(MotorStop());}void react(Call const & e) override {dest_floor = e.floor;if(dest_floor == current_floor)return;/* lambda function used for transition action */auto action = [] { if(dest_floor > current_floor)send_event(MotorUp());else if(dest_floor < current_floor)send_event(MotorDown());};transit<Moving>(action);};
};// ----------------------------------------------------------------------------
// Base state: default implementations
//void Elevator::react(Call const &) {std::cout << "Call event ignored" << std::endl;
}void Elevator::react(FloorSensor const &) {std::cout << "FloorSensor event ignored" << std::endl;
}void Elevator::react(Alarm const &) {transit<Panic>(CallFirefighters);
}int Elevator::current_floor = Elevator::initial_floor;
int Elevator::dest_floor = Elevator::initial_floor;// ----------------------------------------------------------------------------
// Initial state definition
//
FSM_INITIAL_STATE(Elevator, Idle)