c++状态机的使用

article/2025/9/29 16:07:37

什么是状态机

状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。英文名字叫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);}
}

以上示例在单线程下没问题,但若考虑多线程并发,考虑到当一个跳转正在进行的时候,同时又有其他任务请求跳转,则可能会出现数据不一致的问题。 

举个例子:task1(s1, c1/a1 –> s2) 和 task2(s2, c2/a2 –> s3) 先后执行,是可以顺利到达s3状态的,但若操作a1运行的时候,执行权限被task2抢占,则task2此时看到的当前状态还是s1,s1遇到c2就进入陷阱状态,而不会到达s3了,也就是说,状态的跳转发生了不确定,这是不能容忍的。

因此要重新设计状态机,用上队列,把触发事件加入到队列中依次出队和执行。

#include <condition_variable>
#include <mutex>
#include <queue>/** Multiple producer, multiple consumer thread safe queue* Since 'return by reference' is used this queue won't throw */
template <typename T>
class shared_queue
{std::queue<T> queue_;mutable std::mutex m_;std::condition_variable data_cond_;public:shared_queue() = default;shared_queue &operator=(const shared_queue &) = delete;shared_queue(const shared_queue &other) = delete;void push(T item){{std::lock_guard<std::mutex> lock(m_);queue_.push(std::move(item));}data_cond_.notify_one();}/// Try to retrieve, if no items, wait till an item is available and try againvoid wait_and_pop(T &popped_item){std::unique_lock<std::mutex> lock(m_);while (queue_.empty()){data_cond_.wait(lock);//  This 'while' loop is equal to//  data_cond_.wait(lock, [](bool result){return !queue_.empty();});}popped_item = std::move(queue_.front());queue_.pop();}bool wait_and_pop_timed(T &popped_item, std::int64_t duration){std::unique_lock<std::mutex> lock(m_);while (queue_.empty()){auto timeout = data_cond_.wait_for(lock, std::chrono::microseconds(duration));if (timeout == std::cv_status::timeout){return true;}}popped_item = std::move(queue_.front());queue_.pop();return false;}
};

引用

什么是状态机?_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://chatgpt.dhexx.cn/article/O4519HEX.shtml

相关文章

状态机设计举例

⭐本专栏针对FPGA进行入门学习&#xff0c;从数电中常见的逻辑代数讲起&#xff0c;结合Verilog HDL语言学习与仿真&#xff0c;主要对组合逻辑电路与时序逻辑电路进行分析与设计&#xff0c;对状态机FSM进行剖析与建模。 &#x1f525;文章和代码已归档至【Github仓库&#xf…

浅谈状态机

一、状态机原理 &#xff08;一&#xff09;有限状态机 状态机由状态寄存器和组合逻辑电路构成&#xff0c;能够根据控制信号按照预先设定的状态进行状态转移&#xff0c;是协调相关信号动作、完成特定操作的控制中心。有限状态机简写为FSM&#xff08;Finite State Machine&…

状态机与序列机

状态机由状态寄存器和组合逻辑电路构成&#xff0c;能够根据控制信号按照预先设定的状态进行状态转移&#xff0c;是协调相关信号动作、完成特定操作的控制中心。 一、线性序列机 序列机是什么&#xff1a;用计数器对时钟个数计数&#xff0c;根据相应时钟周期下的单个周期时…

状态机总结(简洁)

一、概念 状态机简写为 FSM&#xff08;Finite State Machine&#xff09;&#xff0c;也称为同步有限状态机&#xff0c;我们一般简称为状态机&#xff0c;之所以说“同步”是因为状态机中所有的状态跳转都是在时钟的作用下进行的&#xff0c;而“有限”则是说状态的个数是有…

有限状态机详解(转载)

以前总觉得有限状态机和无限状态机非常的难理解&#xff0c;原来也就是自己一直没有一个直观的认识&#xff0c;今天看到一篇博客&#xff0c;总算对有限状态机入门了。一看就懂。 转载地址&#xff1a;http://blog.csdn.net/zqixiao_09/article/details/50239337 我们知道&a…

状态机

有限状态机&#xff08;Finite State Machine或者Finite State Automata)是软件领域中一种重要的工具&#xff0c;很多东西的模型实际上就是有限状态机。最近看了一些游戏编程AI的材料&#xff0c;感觉游戏中的AI&#xff0c;第一要说的就是有限状态机来实现精灵的AI&#xff0…

状态机的深入理解

目录 1.什么是状态机 2. 生活中的状态机 3. 工程中的应用 4. 发散思考 1.什么是状态机 ■1.1 有向图 有向图是指由定点和边构成的集合&#xff0c;我们常用G&#xff08;E, V&#xff09;来表示一个有向图&#xff0c;其中定点之间由有向边进行连接就构成了有向图。有向图…

有限状态机

文章目录 有限状态机状态机的表示状态转移图二维表 实现穷举法查表法状态模式 总结 有限状态机 有限状态机(Finite State Machine) 缩写为 FSM。以下简称为状态机。 状态机有 3 个组成部分&#xff1a;状态、事件、动作。 状态&#xff1a;所有可能存在的状态。包括当前状态和…

什么是状态机?

前言 状态机在实际工作开发中应用非常广泛&#xff0c;在刚进入公司的时候&#xff0c;根据公司产品做流程图的时候&#xff0c;发现自己经常会漏了这样或那样的状态&#xff0c;导致整体流程会有问题&#xff0c;后来知道了状态机这样的东西&#xff0c;发现用这幅图就可以很…

什么是状态机(Finite-state machine)?

有限状态机 有限状态机(FSM)1、 什么是“状态”2、什么是状态机&#xff1f;3、状态机图怎么画&#xff1f;参考 有限状态机(FSM) 1、 什么是“状态” 先来解释什么是“状态”&#xff08; State &#xff09;。现实事物是有不同状态的&#xff0c;例如一个自动门&#xff0c…

什么是状态机?用C语言实现进程5状态模型

前言 状态机在实际工作开发中应用非常广泛&#xff0c;在刚进入公司的时候&#xff0c;根据公司产品做流程图的时候&#xff0c;发现自己经常会漏了这样或那样的状态&#xff0c;导致整体流程会有问题&#xff0c;后来知道了状态机这样的东西&#xff0c;发现用这幅图就可以很…

状态机(state machine)

一、状态机分类 Mealy状态机:输出取决于输入和当前状态 状态寄存器:由一组触发器组成,用来记忆状态机当前所处的状态,状态的改变只发生在时钟的跳变沿。状态寄存器由一组触发器组成,用来记忆状态机当前所处的状态,状态的改变只发生在时钟的跳变沿。 状态是否改变、如何…

状态机(有限状态自动机 FSM)介绍以及常用状态机种类对比

目录 状态机概念 : 为什么需要状态机: 使用场景 状态机四要素: 常见类型状态机: Squirrel State Machine Spring Statemachine 状态机概念 : 概念 : 状态机是有限状态自动机&#xff08;英语&#xff1a;finite-state machine&#xff0c;缩写&#xff1a;FSM&#xff…

STM32状态机编程----什么是状态机?

万事万物都有其状态 什么是状态 状态是人或事物表现出来的形态。是指现实&#xff08;或虚拟&#xff09;事物处于生成、生存、发展、消亡时期或各转化临界点时的形态或事物态势。 通过上面那句话&#xff0c;我们知道了状态就是一个对象在不同情况下对应的各种形态 做产品的…

什么是状态机?一篇文章就够了

1 概述 状态机[1]一般指有限状态机&#xff08;英语&#xff1a;finite-state machine&#xff0c;缩写&#xff1a;FSM&#xff09;又称有限状态自动机&#xff08;英语&#xff1a;finite-state automaton&#xff0c;缩写&#xff1a;FSA&#xff09;&#xff0c;是表示有限…

C语言_有限状态机(FSM)

C语言_有限状态机&#xff08;Finite State Machine&#xff09; 基本介绍 许多小型或复杂的应用程序都使用有限状态机 (FSM)&#xff0c;C 语言中的有限状态机是嵌入式系统的流行设计模式之一&#xff0c;有限状态机使开发变得容易和顺利。 有很多设备使用事件基态&#xf…

Unity字体展示下载

Unity字体种类展示 这是字体包里面的图片,是不是很多种字体. 下载链接: https://download.csdn.net/download/qq_42603590/12001130 这是下载字体包的地方,很便宜.没有积分的可以留言,我发给你 有时候可能回复的不是很快(抱拳了) 喜欢的话点个赞,关注一下再走吧,谢谢

Unity 之 官网下载地址,方便各个版本的 Unity 安装包下载

Unity 之 官网下载地址&#xff0c;方便各个版本的 Unity 安装包下载 目录 Unity 之 官网下载地址&#xff0c;方便各个版本的 Unity 安装包下载 一、简单介绍 二、各个版本下载入口网址 一、简单介绍 在 Unity 的下载地址现在不是很好找&#xff0c;这里保存一下 Unity 各…

Unity入门之路0-Unity下载安装以及版本选择

文章目录 下载链接Unity Hub和Unity的关系UnityHub下载(Win)两者比较 Unity版本选择许可证问题 下载链接 一定不要百度或者去垃圾网站下载盗版网站 &#xff0c;Unity是正版免费的&#xff0c;官方很关注使用者的感受&#xff0c;所以下载官网的就没问题。 https://unity.cn/re…

UnityHub下载缓存位置

一、下载Unity各版本的编辑器 C:\Users\XXX\AppData\Local\Temp\unityhub-xxx-xxx-xxx-xxx 我电脑是 C:\Users\Administrator\AppData\Local\Temp\unityhub-xxxx-xxxx 如果你不需要备份安装包&#xff0c;那么这个缓存的文件夹&#xff0c;就与你无关了&#xff0c;因为安装完…