当前位置: 首页 > news >正文

开源TinyFSM状态机适用于嵌入式工业平台吗?

文章目录

    • 引言
    • 基于传统 C++ 实现的状态机
    • TinyFSM 实现的对比
    • 现代 C++ 实现的状态机
    • 性能对比
      • TinyFSM 性能测试
      • 传统 C++ 性能测试
      • 现代 C++ 性能测试
    • 工业Misra C++编程标准
    • TinyFSM 的优缺点分析
    • 结论

引言

TinyFSM是一个为C++设计的轻量级有限状态机开源库库。
在嵌入式系统开发中,TinyFSM等状态机适用于控制系统和通信协议等场景,然而,开发者也需考虑该库的性能并考虑是否遵循工业C++标准。
传统 C++ 实现不仅能很容易的满足工业标准的要求,还能提供更高的性能和更低的内存开销。
现代 C++ 实现虽然引入了许多新特性,可以简化代码结构,但在性能上可能不如传统 C++ 实现高效。
反而TinyFSM本身很多地方设计不满足工业C++标准。

基于传统 C++ 实现的状态机

在嵌入式系统中,传统 C++ 实现的状态机通过显式管理状态变量和使用 switch 语句处理事件,可以有效控制内存和运行时开销,同时确保代码符合 MISRA C++ 规范。以下是一个简单的门状态机示例:

#include <iostream>enum class DoorState { Closed, Open, Locked };class DoorStateMachine {
public:DoorStateMachine() : state(DoorState::Closed) {}void open() {switch (state) {case DoorState::Closed:std::cout << "Door is opened\n";state = DoorState::Open;break;case DoorState::Open:std::cout << "Door is already open\n";break;case DoorState::Locked:std::cout << "Cannot open, door is locked\n";break;}}void close() {switch (state) {case DoorState::Closed:std::cout << "Door is already closed\n";break;case DoorState::Open:std::cout << "Door is closed\n";state = DoorState::Closed;break;case DoorState::Locked:std::cout << "Cannot close, door is locked\n";break;}}void lock() {switch (state) {case DoorState::Closed:std::cout << "Door is locked\n";state = DoorState::Locked;break;case DoorState::Open:std::cout << "Cannot lock, door is open\n";break;case DoorState::Locked:std::cout << "Door is already locked\n";break;}}private:DoorState state;
};int main() {DoorStateMachine door;door.open();door.close();door.lock();door.open();return 0;
}

TinyFSM 实现的对比

TinyFSM 是一个轻量级状态机库,通过继承 tinyfsm::Fsm 和定义状态类,能够直观地定义状态和事件处理函数。以下是使用 TinyFSM 实现的门状态机代码:

#include <tinyfsm.hpp>
#include <iostream>struct OpenEvent : tinyfsm::Event {};
struct CloseEvent : tinyfsm::Event {};
struct LockEvent : tinyfsm::Event {};class DoorState : public tinyfsm::Fsm<DoorState> {
public:virtual void react(OpenEvent const &) { std::cout << "Invalid transition\n"; }virtual void react(CloseEvent const &) { std::cout << "Invalid transition\n"; }virtual void react(LockEvent const &) { std::cout << "Invalid transition\n"; }virtual void entry() {}virtual void exit() {}
};class Closed : public DoorState {
public:void react(OpenEvent const &) override {std::cout << "Door is opened\n";transit<Open>();}void react(LockEvent const &) override {std::cout << "Door is locked\n";transit<Locked>();}
};class Open : public DoorState {
public:void react(CloseEvent const &) override {std::cout << "Door is closed\n";transit<Closed>();}
};class Locked : public DoorState {
public:void react(OpenEvent const &) override {std::cout << "Cannot open, door is locked\n";}
};FSM_INITIAL_STATE(DoorState, Closed)int main() {DoorState::start();DoorState::dispatch(OpenEvent());DoorState::dispatch(CloseEvent());DoorState::dispatch(LockEvent());DoorState::dispatch(OpenEvent());return 0;
}

现代 C++ 实现的状态机

现代 C++(如 C++14 和 C++17)引入了许多新特性,使得开发高效、可维护的代码更加容易。在状态机实现中,现代 C++ 特性如 std::functionstd::unordered_map 可以显著简化代码结构。以下是一个基于现代 C++ 实现的状态机示例:

#include <iostream>
#include <functional>
#include <unordered_map>enum class DoorState { Closed, Open, Locked };
enum class DoorEvent { OpenEvent, CloseEvent, LockEvent };class DoorStateMachine {
public:DoorStateMachine() : state(DoorState::Closed) {stateHandlers[DoorState::Closed][DoorEvent::OpenEvent] = [this]() { handleOpenFromClosed(); };stateHandlers[DoorState::Closed][DoorEvent::LockEvent] = [this]() { handleLockFromClosed(); };stateHandlers[DoorState::Open][DoorEvent::CloseEvent] = [this]() { handleCloseFromOpen(); };stateHandlers[DoorState::Locked][DoorEvent::OpenEvent] = [this]() { handleOpenFromLocked(); };}void handleEvent(DoorEvent event) {auto eventHandler = stateHandlers[state].find(event);if (eventHandler != stateHandlers[state].end()) {eventHandler->second();} else {std::cout << "Invalid event\n";}}private:void handleOpenFromClosed() {std::cout << "Door is opened\n";state = DoorState::Open;}void handleLockFromClosed() {std::cout << "Door is locked\n";state = DoorState::Locked;}void handleCloseFromOpen() {std::cout << "Door is closed\n";state = DoorState::Closed;}void handleOpenFromLocked() {std::cout << "Cannot open, door is locked\n";}DoorState state;std::unordered_map<DoorState, std::unordered_map<DoorEvent, std::function<void()>>> stateHandlers;
};int main() {DoorStateMachine door;door.handleEvent(DoorEvent::OpenEvent);door.handleEvent(DoorEvent::CloseEvent);door.handleEvent(DoorEvent::LockEvent);door.handleEvent(DoorEvent::OpenEvent);return 0;
}

性能对比

  • 以下在树莓派5上测试,基本信息如下

    CPU:2.4GHz 四核 64位 Arm Cortex-A76
    内存:32位 LPDDR4X SDRAM,4267MT/s
    
  • 使用了benchmark多次深度压测。

  • 平均数据分别为:

    TinyFSM 传统C++ 现代C++
    5.91 ns 1.25 ns 413 ns

TinyFSM 性能测试

#include <benchmark/benchmark.h>
#include <tinyfsm.hpp>// 事件定义
struct OpenEvent : tinyfsm::Event {};
struct CloseEvent : tinyfsm::Event {};
struct LockEvent : tinyfsm::Event {};// 状态机基类
class DoorState : public tinyfsm::Fsm<DoorState> {public:virtual void react(OpenEvent const &) {}virtual void react(CloseEvent const &) {}virtual void react(LockEvent const &) {}virtual void entry() {}virtual void exit() {}
};// 定义具体状态类
class Closed : public DoorState {public:void react(OpenEvent const &) override { transit<Open>(); }void react(LockEvent const &) override { transit<Locked>(); }
};class Open : public DoorState {public:void react(CloseEvent const &) override { transit<Closed>(); }
};class Locked : public DoorState {public:void react(OpenEvent const &) override {}
};FSM_INITIAL_STATE(DoorState, Closed)static void BM_TinyFSM(benchmark::State &state) {for (auto _ : state) {DoorState::start();DoorState::dispatch(OpenEvent());DoorState::dispatch(CloseEvent());DoorState::dispatch(LockEvent());}
}BENCHMARK(BM_TinyFSM);
BENCHMARK_MAIN();

测试结果

Benchmark           Time             CPU   Iterations
-----------------------------------------------------
BM_TinyFSM       5.91 ns         5.91 ns    116692670

传统 C++ 性能测试

#include <benchmark/benchmark.h>enum class DoorState { Closed, Open, Locked };
enum class DoorEvent { OpenEvent, CloseEvent, LockEvent };class DoorStateMachine {public:DoorStateMachine() : state(DoorState::Closed) {}void handleEvent(DoorEvent event) {switch (state) {case DoorState::Closed:if (event == DoorEvent::OpenEvent) {state = DoorState::Open;} else if (event == DoorEvent::LockEvent) {state = DoorState::Locked;}break;case DoorState::Open:if (event == DoorEvent::CloseEvent) {state = DoorState::Closed;}break;case DoorState::Locked:break;}}private:DoorState state;
};static void BM_TraditionalCPPStateMachine(benchmark::State& state) {DoorStateMachine door;for (auto _ : state) {benchmark::DoNotOptimize(door);door.handleEvent(DoorEvent::OpenEvent);door.handleEvent(DoorEvent::CloseEvent);door.handleEvent(DoorEvent::LockEvent);}
}BENCHMARK(BM_TraditionalCPPStateMachine);BENCHMARK_MAIN();

测试结果:

Benchmark                         Time             CPU   Iterations
-------------------------------------------------------------------
BM_TraditionalCPPStateMachine       1.25 ns         1.25 ns    558856294

现代 C++ 性能测试

#include <benchmark/benchmark.h>
#include <functional>
#include <unordered_map>enum class DoorState { Closed, Open, Locked };
enum class DoorEvent { OpenEvent, CloseEvent, LockEvent };class DoorStateMachine {public:DoorStateMachine() : state(DoorState::Closed) {stateHandlers[DoorState::Closed][DoorEvent::OpenEvent] = [this]() { state = DoorState::Open; };stateHandlers[DoorState::Closed][DoorEvent::LockEvent] = [this]() { state = DoorState::Locked; };stateHandlers[DoorState::Open][DoorEvent::CloseEvent] = [this]() { state = DoorState::Closed; };}void handleEvent(DoorEvent event) {auto eventHandler = stateHandlers[state].find(event);if (eventHandler != stateHandlers[state].end()) {eventHandler->second();}}private:DoorState state;std::unordered_map<DoorState, std::unordered_map<DoorEvent, std::function<void()>>> stateHandlers;
};static void BM_ModernCPPStateMachine(benchmark::State& state) {for (auto _ : state) {DoorStateMachine door;door.handleEvent(DoorEvent::OpenEvent);door.handleEvent(DoorEvent::CloseEvent);door.handleEvent(DoorEvent::LockEvent);}
}BENCHMARK(BM_ModernCPPStateMachine);BENCHMARK_MAIN();

测试结果:

Benchmark                         Time             CPU   Iterations
-------------------------------------------------------------------
BM_ModernCPPStateMachine        413 ns          413 ns      1694224

工业Misra C++编程标准

MISRA C++ 是工业领域的一个要求比较高的标准。以下是一些多态和继承的规则:

  • 规则 10-3-1:虚函数应有明确的用途,避免不必要的虚函数调用。
  • 规则 10-3-2:禁止多重继承。
  • 规则 10-3-3:尽量避免继承深度超过两个层次。
  • 规则 10-3-4:构造函数和析构函数中不应调用虚函数。
  • 规则 10-3-5:禁止多态对象的拷贝和赋值。

TinyFSM 的优缺点分析

优点

  1. 简洁和易用性:通过继承和定义状态类,TinyFSM 使状态和事件处理函数的定义更加直观。
  2. 代码可读性:每个状态独立成类,使状态转换逻辑清晰明了,便于理解和维护。
  3. 减少错误:提供了一个经过验证的框架,降低了手动管理状态转换时的出错风险。
  4. 可扩展性:可以轻松添加新状态和事件,只需定义新的状态类和事件类型。

缺点

  1. 内存使用:使用多态和虚函数增加了对象的内存开销,对于内存资源有限的嵌入式系统可能不太合适。
  2. 运行时开销:虚函数调用需要通过虚表查找实际的函数地址,增加了运行时开销。
  3. 不符合工业编码规范:TinyFSM 不符合严格的工业编码规范(如 MISRA C++)。

结论

总之,工业领域是否要选择TinyFSM还需要三思,尽管现代编程技术如 TinyFSM 对代码结构的简化带来了吸引力,但在需要遵循严格工业标准的环境中,推荐采用更传统的 C++ 编程方法。

http://www.lryc.cn/news/382872.html

相关文章:

  • EE trade:利弗莫尔三步建仓法
  • Java中Callable的应用
  • 测试卡无法仪表注册问题分析
  • 【扩散模型(一)】Stable Diffusion中的重建分支(reconstruction branch)和条件分支(condition branch)
  • WPF——Binding
  • linux与windows环境下qt程序打包教程
  • LeetCode21-合并两个有序链表
  • 嵌入式学习——数据结构(双向无头无环链表)——day47
  • MYSQL 将某个字段赋值当前时间
  • ModelSim® SE Command Reference Manual : find命令的用法
  • PHPMailer发送的中文内容乱码如何解决
  • .npmrc配置文件
  • 无线桥接两个路由器 实现全屋网络全覆盖
  • qt开发-14_QListwidget 仿qq好友列表制作
  • 基于hutool的sm2非对称加密使用示例
  • 深入Scala的变量声明与类型推断:语法糖下的智能推导
  • ATA-4052C高压功率放大器在新能源汽车安全测试中的应用
  • liunx打开谷歌报错
  • ICMAN液位检测大盘点
  • 2024软件设计师笔记之考点版(一考就过):1-10
  • Java中的性能优化技巧
  • 一位Java软件开发工程师繁忙的一天
  • 容易上手的AI图片生成软件有哪些值得推荐?
  • 如何高效运营交友APP
  • 使用@Lazy注解解决循环依赖的问题
  • manim边学边做--SingleStringMathTex
  • 4、双足机器人mpc基础概念
  • 论坛实现随机发帖的学习
  • 麒麟系统设置jar开机自启动自定义服务
  • WebPages 全局