c++状态机的使用

news/2024/4/20 3:09:12/

什么是状态机

状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。英文名字叫State Machine ,不是指一台实际机器,一般就是指一张状态转换图。全称是有限状态自动机,自动两个字包含重要含义。给定一个状态机,同时给定它的当前状态以及输入,那么输出状态时可以明确的运算出来的,当输入条件时,能输出下一个状态。

现实事物是有不同状态,例如一个LED等,就有 亮 和 灭两种状态。我们通常所说的状态机是有限状态机,也就是被描述的事物的状态的数量是有限个,例如LED灯的状态就是两个亮和 灭。

在这里插入图片描述

为什么用状态机

状态机解决的问题就是当某种模型的状态变更比较比较复杂,且状态比较多,那么我们有必要将这些状态变化的逻辑抽象出来,做成一个可以统一调用的算法,这样封装出来的代码就比较好维护,同时可读性也很强。

状态机在实际工作开发中很有用,应用也非常广泛。一个健壮的状态机可以让你的程序,不论发生何种突发事件都不会突然进入一个不可预知的程序分支,可以很清晰的表达整个状态的流转。

在GUI应用程序、Web应用程序等事件驱动型的应用程序,采用状态机的思路来完成程序设计,可以简化设计流程,使程序的可读性、可维护性都得到增加。

 使用状态机有哪些好处?
1. 当一个程序有多个状态时,规范了状态机的状态转换,避免了一些引入一些复杂的判断逻辑。
2. 规范了程序在不同状态下所能提供的能力。
3. 在能力上可以进行横向扩展,提供新的状态来完善现有逻辑。

简单状态机的实现

使用switch跳转即可实现一种简单的状态机。如果逻辑不是很复杂,使用switch语句也能达到实现目的。举例如下:

enum state{nullState_,firstState_,secondState_,thirdState_,quitState_,};struct param_t{int param1;int param2;
// ......};int nullStateProc(param_t& param){return firstState_;
}int firstStateProc(param_t& param){return secondState_;
}int secondStateProc(param_t& param){return secondState_;
}int thirdStateProc(param_t& param){return secondState_;
}int quitEvent(){return nullState_;
}int stateMachine(state& state_, param_t& param){switch (state_){case nullState_:state_ = static_cast<state>(nullStateProc(param));break;case firstState_:state_ = static_cast<state>(firstStateProc(param));break;case secondState_:state_ = static_cast<state>(secondStateProc(param));break;case thirdState_:state_ = static_cast<state>(thirdStateProc(param));break;case quitState_:quitEvent();return 0;}return 1;}void start()
{state state_ = nullState_;param_t param{};while (true){auto stateResult = stateMachine(state_, param);if (!stateResult){return;}}
}

另一种简单实现

如果需要管理的状态和事件比较多,需要逻辑清晰和便于维护,使用简单的switch可能无法满足需求。这里介绍一种简单的实现,消除庞大的条件分支语句,从配置表容易看出各个状态的转换图。

/*  statemachine.h*/#ifndef _STATEMACHINE_H_
#define _STATEMACHINE_H_#include <iostream>enum EventActionResult {EventFailed, EventProcessedOK
};template<class T, class P>
class State {
public:std::string inputEvent;State<T, P> *nextState;EventActionResult (T::*action)(const std::string &event, P *param);State<T, P> *errorState;
};template<class T, class P>
class StateMachine {
private:State<T, P> *init;State<T, P> *current;T *target;public:StateMachine() {}void Init(T *_target, State<T, P> *initialState) {init = current = initialState;target = _target;}void Reset() {current = init;}void ProcessEvent(const std::string &event, P *param) {for (State<T, P> *p = this->current; p->nextState != NULL; p++) {if (p->inputEvent == event) {if (p->action != NULL) {if (EventFailed == (this->target->*(p->action))(event, param)) {if (p->errorState != NULL) {//Only if there's an errorstate defined. Otherwise, just do nothingthis->current = p->errorState;}return;}}this->current = p->nextState;return;}}//Event not found. Do nothingreturn;}
};

以下是使用举例:

class MyStateMachine {
public:struct param_t {int param;int param1;int param2;};StateMachine<MyStateMachine, param_t> stMachine;EventActionResult HandleEvent1(const std::string &e, param_t *param);EventActionResult HandleEvent2(const std::string &e, param_t *param);EventActionResult HandleEventA(const std::string &e, param_t *param);EventActionResult HandleEventB(const std::string &e, param_t *param);EventActionResult HandleThree(const std::string &e, param_t *param);void HandleEvent(const std::string &e, param_t *param);void Init();void Start();
};
#include "statemachine.h"
#include <cstdlib>
#include <iostream>
#include <stdio.h>typedef State<MyStateMachine, MyStateMachine::param_t> STATE;extern STATE Idle[];
extern STATE One[];
extern STATE Two[];STATE Idle[] ={//EVENT,NEXT,  ACTION,   ERRORSTATE (where to land if there's an error){"event1", One, &MyStateMachine::HandleEvent1, Idle},{"event2", Two, &MyStateMachine::HandleEvent2, Idle},{"", NULL, NULL, NULL}, //End of table};STATE One[] ={{"eventA", Idle, &MyStateMachine::HandleEventA, Idle},{"eventB", Idle, &MyStateMachine::HandleEventB, Idle},{"", NULL, NULL, NULL},};STATE Two[] ={{"eventC", Idle, NULL, NULL},{"", NULL,  NULL, NULL},};EventActionResult MyStateMachine::HandleEvent1(const std::string &e, param_t *param) {std::cout << "HandleEvent1,param:" << param->param << std::endl;return EventProcessedOK;
}EventActionResult MyStateMachine::HandleEvent2(const std::string &e, param_t *param) {std::cout << "HandleEvent2,param:" << param->param << std::endl;return EventProcessedOK;
}EventActionResult MyStateMachine::HandleEventA(const std::string &e, param_t *param) {std::cout << "HandleEventA,param:" << param->param << std::endl;return EventProcessedOK;
}EventActionResult MyStateMachine::HandleEventB(const std::string &e, param_t *param) {std::cout << "HandleEventB,param:" << param->param << std::endl;return EventProcessedOK;
}EventActionResult MyStateMachine::HandleThree(const std::string &e, param_t *param) {std::cout << "HandleThree" << std::endl;return EventProcessedOK;
}void MyStateMachine::HandleEvent(const std::string &e, param_t *param) {stMachine.ProcessEvent(e, param);
}void MyStateMachine::Init() {stMachine.Init(this, Idle);
}void MyStateMachine::Start() {while (1) {char c[255];// 模拟输入eventstd::cin.getline(c,255);std::string event{c};MyStateMachine::param_t param;param.param = 1;this->HandleEvent(event, &param);}
}

引用

什么是状态机?_pingxiaozhao的博客-CSDN博客_状态机的概念

为Linux应用构造有限状态机_wowocpp的博客-CSDN博客_linux 状态机

有限状态机详解(转载)_白小狮的博客-CSDN博客_有限状态机和无限状态机

Linux进程是如何创建出来的?

为Linux操作系统应用构造有限状态机方法-红联Linux系统门户

一文详解 Android状态机StateMachine 使用方式及实现原理_bjxiaxueliang的博客-CSDN博客_statemachine

c++写状态机_zhi_cary的博客-CSDN博客_c++ 状态机

C++有限状态机的实现_Valreaper的博客-CSDN博客_c++ 状态机

github经典C++状态机(fsm)源代码剖析_star-keke的博客-CSDN博客

用C++来实现有限状态机(附代码)_李肖遥的博客-CSDN博客

TinyFSM 介绍_百思可乐的博客-CSDN博客

C++状态机框架实现 - 灰信网(软件开发博客聚合)

状态模式(state)C++实现_shu_chang1993的博客-CSDN博客_c++state

c++写状态机_zhi_cary的博客-CSDN博客_c++ 状态机


http://www.ppmy.cn/news/2560.html

相关文章

JAVA基础讲义04-方法

重要性&#xff1a;&#x1f60d;&#x1f60d;&#x1f60d;&#x1f60d;&#x1f60d; JAVA基础讲义-04方法1.1 java方法概述1.2 方法定义的格式1.3 方法分类1.4 方法格式详解1.5 演示1.6 方法案例1.6.2 方法的调用方式1.7 方法重载介绍1.7.1 方法重载介绍1.7.2 代码实现方法…

vue.js:组件化的实现和使用过程

什么是组件化&#xff1f; 当我们遇到复杂问题的时候&#xff1a; 任何一个人处理信息的逻辑能力都是有限的所以&#xff0c;当我们面对一个复杂的问题的时候&#xff0c;我们不可能一次性搞定处理掉一大堆内容但是我们都会有问题拆解的能力将一个复杂的问题拆解成很多小的问…

学会这些C语言技巧,你的编程能力大大提升

一、函数指针 在讲回调函数之前&#xff0c;我们需要了解函数指针。 我们都知道&#xff0c;C语言的灵魂是指针&#xff0c;我们经常使用整型指针&#xff0c;字符串指针&#xff0c;结构体指针等 int *p1; char *p2; STRUCT *p3; //STRUCT为我们定义的结构体 但是好像我们…

Kubernetes那点事儿——日志管理

K8s日志管理前言一、日志二、K8s应用日志标准输出应用日志收集1、emptyDir挂载收集2、边车容器收集前言 程序运行中输出的日志默认暂存在Pod中&#xff0c;当Pod销毁重建时&#xff0c;日志也会丢失。所以需要一些持久化的方法保存程序日志。 一、日志 K8s系统日志 kubelet组件…

【Paper】2021_具有输入饱和的多智能体系统非负连边比例一致性研究_范志鹏

范志鹏. 具有输入饱和的多智能体系统非负连边比例一致性研究[D].华中科技大学,2021.DOI:10.27157/d.cnki.ghzku.2021.001324. 文章目录3 基于状态反馈的线性离散正系统连边比例一致性控制3.1 引言3.2 基于状态反馈的离散时间连边比例一致性的问题描述3.3 无向网络离散时间连边比…

C语言实现一个闪烁的圣诞树(控制台)

下下下周就是圣诞节啦&#xff0c;C语言的圣诞树必须安排起&#xff01;&#xff01;&#xff01; 效果展示&#xff1a; 原理说明&#xff1a; 函数 layer 画出树的层次&#xff0c;根据坐标来输出位置&#xff1b; void layer(int x, int y, int num, int col) 函数 tri…

【有营养的算法笔记】归并排序

&#x1f451;作者主页&#xff1a;进击的安度因 &#x1f3e0;学习社区&#xff1a;进击的安度因&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;有营养的算法笔记 文章目录一、思路二、模板讲解三、模板测试四、加练 —— 逆序对的数量今天讲解的内容是…

Alvas.Audio专门为C#和VB.Net程序员设计

Alvas.Audio专门为C#和VB.Net程序员设计 Alvas.Audio库使C#和VB.Net程序员能够创建执行(包括混合声音信息)、捕获、转换和编辑音频的应用程序。 Alvas.Audio音频是C#音乐库。Web程序员。 这使您能够生产。NET程序&#xff0c;例如Winforms/WPF/Windows服务/控制台录音机、Inter…

机器学习-模型评估与选择(待更新)

本章主要讲解机器学习的基础知识&#xff0c;有关一些专业术语的定义与解释。 文章目录2.1 经验误差与过拟合2.2 评估方法2.2.1 留出法2.2.2 交叉验证法2.2.3 自助法2.2.4 调参与最终模型2.3 性能度量2.3.1 错误率与精度2.3.2 查准率、查全率与F12.3.3 ROC与AUC2.1 经验误差与过…

观看2022年卡塔尔世界杯的感想

每四年一度的世界杯又开始了&#xff0c;刚好在假期&#xff0c;这可是自我懂事以来第一次认真的观看。每到有球赛时我们父子齐上阵&#xff0c;摩拳擦掌、看到精彩时不忘高声齐呼&#xff0c;于是客厅就变成我们爷俩的绿茵场了。 几场下来&#xff0c;我只看到白皮肤&…

windows几个常用的命令

1. net命令 查看用户列表: net user powershell查看用户列表: Get-WmiObject -Class Win32_UserAccount 查看用户组列表: net localgroup 查看管理组列表: net localgroup Administrators 添加用户并设置密码: net user ASP.NET Pssw0rd /add 将用户加入管理组: net localgrou…

[附源码]JAVA毕业设计田径运动会管理系统(系统+LW)

[附源码]JAVA毕业设计田径运动会管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技…

AT_pakencamp_2021_day2 a~c 题解

目录A题&#xff08;AT_pakencamp_2021_day2_a Participants 2 &#xff09;题目大意思路CODEB题&#xff08;AT_pakencamp_2021_day2_b Pasokon Power &#xff09;思路CODEC题&#xff08;AT_pakencamp_2021_day2_c Participants 3 &#xff09;题目翻译思路CODEA题&#xff…

(附源码)SSM失物招领平台 毕业设计 271621

SSM失物招领平台的设计与实现 摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对失物招领等问…

使用formatter方法格式化数据

前言 当你在表格中根据标识展示不同字段时&#xff0c;你发现&#xff0c;这个标识的类型有很多&#xff0c;需要一个一个判断很多行代码。当然&#xff0c;标识的类型比较少时&#xff0c;直接通过判断展示不同的字段无疑是最快的&#xff0c;如下代码。一旦匹配的标识类型有几…

【Golang】欲入此Go先看Go的基本语法

&#x1f4d3;推荐网站(不断完善中)&#xff1a;个人博客 &#x1f4cc;个人主页&#xff1a;个人主页 &#x1f449;相关专栏&#xff1a;CSDN专栏、个人专栏 &#x1f3dd;立志赚钱&#xff0c;干活想躺&#xff0c;瞎分享的摸鱼工程师一枚 &#x1f34a;前言 完成了我们众多…

【与达梦同行】数据库coredump的几种常用生成方式+dmrdc使用

一、简介 DM 实例故障&#xff0c;即数据库进程 dmserver 出现异常&#xff0c;表现为异常中止&#xff0c;进程存在但无响应或者无法登录的状态&#xff0c;出现此类问题都属于比较严重的故障&#xff0c;一般情况下我们需要尽可能的收集到所需要的信息进行故障分析&#xff…

Qt实现跨平台窗口选择功能

Qt实现跨平台获取鼠标位置窗口大小功能 文章目录Qt实现跨平台获取鼠标位置窗口大小功能1、概述2、实现效果3、实现原理4、关键代码5、源代码更多精彩内容&#x1f449;个人内容分类汇总 &#x1f448;&#x1f449;Qt自定义模块、工具&#x1f448; 1、概述 Qt版本&#xff1a…

(vsCode) sqlite3可视化工具的使用

vsCode - sqlite3可视化工具的使用 1.安装扩展 SQLite 因此&#xff0c;我们将引入一个名为 SQLite的扩展。 尝试照常从VScode Marketplace安装&#xff1a;搜索SQLite 安装扩展 2.如何使用SQLite&#xff1a; 打开命令选项板&#xff0c;然后输入 sql。 具体操作&#xff1…

IT培训从业6年, 正厚软件魏老师说些真心话(篇一)

其实每个行业都有一些为人知和不为人广知的信息, 称之为"路子"&#xff0c;只要说话发声吧总会有人不满意。引发的廉价的口水战, 更有甚者不知其居心的人愤然的各种神一般的操作, 我也见怪不怪了…… 可能部分文字触及一些一些利益, 但是还是想给一些准备入IT行业/软…