文章目录
0. 引言
在软件开发中,有限状态机(Finite State Machine,FSM)是一种重要的设计模式,广泛应用于系统建模、控制流管理和事件驱动程序设计。本文将介绍如何使用轻量级的 C++ 状态机库 tinyFSM 来实现一个有限状态机,从状态图描述到代码实现的全过程。
1. 状态机描述
如上图状态机,其流程可以用以下方式描述:
- 状态 A:初始状态,可能包含一些子状态。
- 状态 B:可通过满足特定条件从状态 A 转换而来。
- 故障状态:当状态转换失败或条件不满足时进入的状态。
1.1 状态和转换
-
状态 A:
- 子状态:状态 A 包含以下子状态:
- 子状态 1
- 子状态 2
- 子状态 3
- 子状态 4
- 子状态 5
- 转换条件:
- 当满足条件
condition1
和condition2
时,可以从状态 A 转换到状态 B。 - 如果条件不满足,转换将失败,进入故障状态。
- 当满足条件
- 子状态:状态 A 包含以下子状态:
-
状态 B:
- 转换条件:
- 当满足条件
condition3
时,可以从状态 B 转换回状态 A。 - 如果条件不满足,转换将失败,进入故障状态。
- 当满足条件
- 转换条件:
-
故障状态:
- 系统进入此状态后,需要处理错误或重置状态机。
1.2 枚举类
我们定义了一个枚举类 StatusFeedback
,包含以下状态:
UNDEFINED
:未定义状态。STATE_A
:状态 A。STATE_B
:状态 B。FAILURE
:故障状态。
2. tinyFSM 简介
tinyFSM 是一个用现代 C++ 编写的轻量级有限状态机库。它的特点包括:
- 轻量级、易于集成,无第三方依赖。
- 使用模板元编程,实现编译时多态,性能高效。
- 支持事件驱动的状态转换。
3. 代码实现
下面我们使用 tinyFSM 来实现上述状态机。
3.1. 定义状态反馈枚举
引入头文件和命名空间
#include <iostream>
#include "tinyfsm.hpp"
enum class StatusFeedback
{
UNDEFINED,
STATE_A,
STATE_B,
FAILURE
};
3.2 定义事件
// 从状态 A 到状态 B 的事件
struct EvAtoB : tinyfsm::Event
{
bool condition1;
bool condition2;
EvAtoB(bool cond1 = false, bool cond2 = false)
: condition1(cond1), condition2(cond2) {}
};
// 从状态 B 到状态 A 的事件
struct EvBtoA : tinyfsm::Event
{
bool condition3;
EvBtoA(bool cond3 = false)
: condition3(cond3) {}
};
// 故障事件
struct EvFailure : tinyfsm::Event { };
3.3 定义基状态类
class BaseState : public tinyfsm::Fsm<BaseState>
{
public:
// 默认事件处理(未定义的事件)
void react(EvAtoB const &) { }
void react(EvBtoA const &) { }
void react(EvFailure const &) { }
virtual void entry() { } // 进入状态时的动作
virtual void exit() { } // 离开状态时的动作
// 获取当前状态反馈
virtual StatusFeedback getStatus() const = 0;
};
3.4 前向声明具体状态类
class StateA;
class StateB;
class FailureState;
3.5 定义具体状态类
3.5.1 状态 A
class StateA : public BaseState
{
public:
// 定义子状态
enum class Substate
{
Substate1,
Substate2,
Substate3,
Substate4,
Substate5
};
Substate substate;
void entry() override
{
std::cout << "进入状态 A" << std::endl;
// 设置初始子状态
substate = Substate::Substate1;
}
void exit() override
{
std::cout << "离开状态 A" << std::endl;
}
void react(EvAtoB const & event) override
{
std::cout << "状态 A:收到 EvAtoB" << std::endl;
// 检查条件
if (event.condition1 && event.condition2)
{
std::cout << "从状态 A 转换到状态 B" << std::endl;
transit<StateB>();
}
else
{
std::cout << "条件不满足,进入故障状态" << std::endl;
transit<FailureState>();
}
}
void react(EvFailure const &) override
{
std::cout << "状态 A:收到 EvFailure,进入故障状态" << std::endl;
transit<FailureState>();
}
StatusFeedback getStatus() const override
{
return StatusFeedback::STATE_A;
}
// 可添加处理子状态转换的额外方法
};
3.5.2 状态 B
class StateB : public BaseState
{
public:
void entry() override
{
std::cout << "进入状态 B" << std::endl;
}
void exit() override
{
std::cout << "离开状态 B" << std::endl;
}
void react(EvBtoA const & event) override
{
std::cout << "状态 B:收到 EvBtoA" << std::endl;
// 检查条件
if (event.condition3)
{
std::cout << "从状态 B 转换到状态 A" << std::endl;
transit<StateA>();
}
else
{
std::cout << "条件不满足,进入故障状态" << std::endl;
transit<FailureState>();
}
}
void react(EvFailure const &) override
{
std::cout << "状态 B:收到 EvFailure,进入故障状态" << std::endl;
transit<FailureState>();
}
StatusFeedback getStatus() const override
{
return StatusFeedback::STATE_B;
}
};
3.5.3 故障状态
class FailureState : public BaseState
{
public:
void entry() override
{
std::cout << "进入故障状态" << std::endl;
}
void exit() override
{
std::cout << "离开故障状态" << std::endl;
}
StatusFeedback getStatus() const override
{
return StatusFeedback::FAILURE;
}
};
4. 主函数
定义状态列表和初始状态
// 定义状态列表
using FsmList = tinyfsm::FsmList<StateA, StateB, FailureState>;
// 设置初始状态为 StateA
FSM_INITIAL_STATE(BaseState, StateA)
int main()
{
// 启动状态机
FsmList::start();
// 获取当前状态
BaseState *currentState = &BaseState::state();
std::cout << "当前状态编号:" << static_cast<int>(currentState->getStatus()) << std::endl;
// 尝试在条件不满足的情况下从状态 A 转换到状态 B
EvAtoB ev_a2b(false, false);
FsmList::dispatch(ev_a2b);
// 在条件满足的情况下从状态 A 转换到状态 B
EvAtoB ev_a2b_ok(true, true);
FsmList::dispatch(ev_a2b_ok);
// 从状态 B 转换回状态 A
EvBtoA ev_b2a(true);
FsmList::dispatch(ev_b2a);
// 从状态 A 触发故障事件
EvFailure ev_failure;
FsmList::dispatch(ev_failure);
return 0;
}
5. 运行结果
编译并运行上述代码,得到以下输出:
进入状态 A
当前状态编号:1
状态 A:收到 EvAtoB
条件不满足,进入故障状态
离开状态 A
进入故障状态
状态 A:收到 EvAtoB
状态 A:收到 EvAtoB
从状态 A 转换到状态 B
离开状态 A
进入状态 B
状态 B:收到 EvBtoA
从状态 B 转换到状态 A
离开状态 B
进入状态 A
状态 A:收到 EvFailure,进入故障状态
离开状态 A
进入故障状态
6. 代码解析
6.1 状态转换逻辑
- 状态 A 到状态 B:当收到事件
EvAtoB
且condition1
和condition2
均为true
时,状态 A 转换到状态 B;否则,进入故障状态。 - 状态 B 到状态 A:当收到事件
EvBtoA
且condition3
为true
时,状态 B 转换到状态 A;否则,进入故障状态。 - 故障状态处理:当任何状态收到
EvFailure
事件或条件不满足时,进入故障状态。
6.2 子状态管理
- 在状态 A 中,定义了一个枚举
Substate
来表示子状态。进入状态 A 时,默认子状态为Substate1
。 - 可以根据需要在状态 A 中添加处理子状态转换的逻辑。
6.3 状态反馈
- 使用
getStatus()
方法获取当前状态的反馈,可以用于监控和日志记录。
6.4 为什么 EvFailure
事件只影响了 状态 A 而不是 状态 B?
EvFailure ev_failure;
FsmList::dispatch(ev_failure);
这段代码为啥只打印如下:“状态 A:收到 EvFailure,进入故障状态” ,状态B为什么没有进入故障状态?
原因
在 tinyFSM 中,事件只会被派发给当前的活动状态,即状态机中的唯一一个处于活动状态的状态会对事件作出反应。对于您当前的代码来说,事件 EvFailure
只会发送给当前处于活动状态的状态,而不会广播给所有状态。
在您的程序运行时,状态 A 是当前的活动状态。所以当 EvFailure
被派发时,状态 A 对该事件作出了反应,并转换到 故障状态。因此输出:
状态 A:收到 EvFailure,进入故障状态
状态 B 没有收到 EvFailure
的原因是:状态 B 在事件派发时不是当前的活动状态,因此不会对事件作出反应。
具体流程
让我们按步骤分析一下代码的运行流程,帮助更清楚地理解:
-
启动状态机:当程序启动时,状态机被初始化,并设置为从 状态 A 开始。
- 输出:
进入状态 A
- 输出:
-
触发
EvAtoB
事件(条件不满足):-
当前状态:状态 A
-
事件:
EvAtoB
,条件不满足(condition1 = false
,condition2 = false
)。 -
状态 A 检查事件条件,条件不满足,于是它进入 故障状态。
-
输出:
状态 A:收到 EvAtoB 条件不满足,进入故障状态 离开状态 A 进入故障状态
-
-
触发
EvAtoB
事件(条件满足):-
当前状态:故障状态
-
事件:
EvAtoB
,条件满足(condition1 = true
,condition2 = true
)。 -
故障状态 对
EvAtoB
不作出反应,因为它没有处理EvAtoB
事件的逻辑。故障状态会忽略这个事件。 -
没有输出,因为没有任何反应。
-
-
从状态 A 触发
EvFailure
事件:-
当前状态:状态 A
-
事件:
EvFailure
-
状态 A 对
EvFailure
事件作出反应,进入 故障状态。 -
输出:
状态 A:收到 EvFailure,进入故障状态 离开状态 A 进入故障状态
-
7. 附录:完整代码
// g++ -std=c++11 -o fsm_example main.cpp
#include <iostream>
#include "tinyfsm.hpp"
// 定义状态反馈枚举
enum class StatusFeedback
{
UNDEFINED,
STATE_A,
STATE_B,
FAILURE
};
// 定义事件
// 从状态 A 到状态 B 的事件
struct EvAtoB : tinyfsm::Event
{
bool condition1;
bool condition2;
EvAtoB(bool cond1 = false, bool cond2 = false)
: condition1(cond1), condition2(cond2) {}
};
// 从状态 B 到状态 A 的事件
struct EvBtoA : tinyfsm::Event
{
bool condition3;
EvBtoA(bool cond3 = false)
: condition3(cond3) {}
};
// 故障事件
struct EvFailure : tinyfsm::Event { };
// 定义基状态类
class BaseState : public tinyfsm::Fsm<BaseState>
{
public:
// 默认事件处理(未定义的事件)
void react(EvAtoB const &) { }
void react(EvBtoA const &) { }
void react(EvFailure const &) { }
virtual void entry() { } // 进入状态时的动作
virtual void exit() { } // 离开状态时的动作
// 获取当前状态反馈
virtual StatusFeedback getStatus() const = 0;
};
// 前向声明具体状态类
class StateA;
class StateB;
class FailureState;
// 定义具体状态类
// 状态 A
class StateA : public BaseState
{
public:
// 定义子状态
enum class Substate
{
Substate1,
Substate2,
Substate3,
Substate4,
Substate5
};
Substate substate;
void entry() override
{
std::cout << "进入状态 A" << std::endl;
// 设置初始子状态
substate = Substate::Substate1;
}
void exit() override
{
std::cout << "离开状态 A" << std::endl;
}
void react(EvAtoB const & event) override
{
std::cout << "状态 A:收到 EvAtoB" << std::endl;
// 检查条件
if (event.condition1 && event.condition2)
{
std::cout << "从状态 A 转换到状态 B" << std::endl;
transit<StateB>();
}
else
{
std::cout << "条件不满足,进入故障状态" << std::endl;
transit<FailureState>();
}
}
void react(EvFailure const &) override
{
std::cout << "状态 A:收到 EvFailure,进入故障状态" << std::endl;
transit<FailureState>();
}
StatusFeedback getStatus() const override
{
return StatusFeedback::STATE_A;
}
// 可添加处理子状态转换的额外方法
};
// 状态 B
class StateB : public BaseState
{
public:
void entry() override
{
std::cout << "进入状态 B" << std::endl;
}
void exit() override
{
std::cout << "离开状态 B" << std::endl;
}
void react(EvBtoA const & event) override
{
std::cout << "状态 B:收到 EvBtoA" << std::endl;
// 检查条件
if (event.condition3)
{
std::cout << "从状态 B 转换到状态 A" << std::endl;
transit<StateA>();
}
else
{
std::cout << "条件不满足,进入故障状态" << std::endl;
transit<FailureState>();
}
}
void react(EvFailure const &) override
{
std::cout << "状态 B:收到 EvFailure,进入故障状态" << std::endl;
transit<FailureState>();
}
StatusFeedback getStatus() const override
{
return StatusFeedback::STATE_B;
}
};
// 故障状态
class FailureState : public BaseState
{
public:
void entry() override
{
std::cout << "进入故障状态" << std::endl;
}
void exit() override
{
std::cout << "离开故障状态" << std::endl;
}
StatusFeedback getStatus() const override
{
return StatusFeedback::FAILURE;
}
};
// 定义状态列表
using FsmList = tinyfsm::FsmList<StateA, StateB, FailureState>;
// 设置初始状态为 StateA
FSM_INITIAL_STATE(BaseState, StateA)
int main()
{
// 启动状态机
FsmList::start();
// 获取当前状态
BaseState *currentState = &BaseState::state();
std::cout << "当前状态编号:" << static_cast<int>(currentState->getStatus()) << std::endl;
// 尝试在条件不满足的情况下从状态 A 转换到状态 B
EvAtoB ev_a2b(false, false);
FsmList::dispatch(ev_a2b);
// 在条件满足的情况下从状态 A 转换到状态 B
EvAtoB ev_a2b_ok(true, true);
FsmList::dispatch(ev_a2b_ok);
// 从状态 B 转换回状态 A
EvBtoA ev_b2a(true);
FsmList::dispatch(ev_b2a);
// 从状态 A 触发故障事件
EvFailure ev_failure;
FsmList::dispatch(ev_failure);
return 0;
}