没有合适的资源?快使用搜索试试~ 我知道了~
首页C语言中的状态机设计深入讲解
C语言中的状态机设计深入讲解
24 下载量 139 浏览量
更新于2023-03-03
评论 1
收藏 153KB PDF 举报
前言 本文不是关于软件状态机的最佳设计分解实践的教程。我将重点关注状态机代码和简单的示例,这些示例具有足够的复杂性,以便于理解特性和用法。 背景 大多数程序员常用的设计技术是有限状态机(FSM)。设计人员使用此编程结构将复杂的问题分解为可管理的状态和状态转换。有无数种实现状态机的方法。 A switch语句提供了状态机最容易实现和最常见的版本之一。在这里,每个案例在switch语句成为一个状态,实现如下所示: switch (currentState) { case ST_IDLE: // do something in the idle state break; case ST_S
资源详情
资源评论
资源推荐
C语言中的状态机设计深入讲解语言中的状态机设计深入讲解
前言前言
本文不是关于软件状态机的最佳设计分解实践的教程。我将重点关注状态机代码和简单的示例,这些示例具有足够的复杂性,
以便于理解特性和用法。
背景背景
大多数程序员常用的设计技术是有限状态机(FSM)。设计人员使用此编程结构将复杂的问题分解为可管理的状态和状态转换。
有无数种实现状态机的方法。
A switch语句提供了状态机最容易实现和最常见的版本之一。在这里,每个案例在switch语句成为一个状态,实现如下所示:
switch (currentState) {
case ST_IDLE:
// do something in the idle state
break;
case ST_STOP:
// do something in the stop state
break;
// etc...
}
这种方法当然适合于解决许多不同的设计问题。然而,在事件驱动的多线程项目上使用时,这种形式的状态机可能是非常有限
的。
第一个问题是控制哪些状态转换是有效的,哪些是无效的。无法强制执行状态转换规则。任何过渡都可以在任何时候进行,这
并不是特别可取的。对于大多数设计,只有少数转换模式是有效的。理想情况下,软件设计应该强制执行这些预定义的状态序
列,并防止不必要的转换。当试图将数据发送到特定状态时,会出现另一个问题。由于整个状态机位于单个函数中,因此向任
何给定状态发送额外数据都是困难的。最后,这些设计很少适合在多线程系统中使用。设计器必须确保状态机是从单个控制线
程调用的。
为什么要用国家机器?为什么要用国家机器?
使用状态机实现代码是解决复杂工程问题的一种非常方便的设计技术。状态机将设计分解为一系列步骤,或在状态机术语中称
为状态。每个状态都执行一些狭义的任务。另一方面,事件是一种刺激,它导致状态机在状态之间移动或过渡。
举一个简单的例子,我将在本文中使用它,假设我们正在设计电机控制软件。我们想启动和停止电机,以及改变电机的速度。
很简单。向客户端软件公开的电机控制事件如下:
设定速度-设定电机以特定速度行驶
站住-停止马达
这些事件提供了以任何速度启动电机的能力,这也意味着改变已经移动的电机的速度。或者我们可以完全停止马达。对于电机
控制模块,这两个事件或功能被认为是外部事件.然而,对于使用我们的代码的客户机来说,这些只是普通的函数。
这些事件不是状态机状态。处理这两个事件所需的步骤是不同的。在这种情况下,各州是:
闲散-马达不是旋转的,而是静止的
无所事事
启动-从死胡同启动马达
开启电动机电源
设定电机转速
变速-调整已经移动的马达的速度
改变电机转速
停-停止移动的马达
关闭电动机电源
进入闲置状态
可以看出,将电机控制分解为离散状态,而不是单一的功能,我们可以更容易地管理如何操作电机的规则。
每个状态机都有“当前状态”的概念。这是状态机当前所处的状态。在任何给定的时刻,状态机只能处于单一状态。特定状态机
实例的每个实例在定义时都可以设置初始状态。但是,该初始状态在对象创建期间不执行。只有发送到状态机的事件才会导致
执行状态函数。
为了图形化地说明状态和事件,我们使用状态图。下面的图1显示了电机控制模块的状态转换。框表示状态,连接箭头表示事
件转换。列出事件名称的箭头是外部事件,而未装饰的行被认为是内部事件。(本文后面将介绍内部事件和外部事件之间的差
异。)
图1:电机状态图
如您所见,当事件在状态转换中出现时,所发生的状态转换取决于状态机的当前状态。当SetSpeed事件出现,例如,电机在
Idle状态,则转换为Start状态。然而,同样的SetSpeed当前状态为Start将电机转换为ChangeSpeed状态。您还可以看到,并
非所有的状态转换都是有效的。例如,马达不能从ChangeSpeed到Idle而不需要先通过Stop状态。
简而言之,使用状态机捕获和执行复杂的交互,否则可能很难传递和实现。
内外事件内外事件
正如我前面提到的,事件是导致状态机在状态之间转换的刺激。例如,按下按钮可能是一个事件。事件可以分为两类:外部事
件和内部事件。外部事件,在其最基本的级别上,是对状态机模块的函数调用.这些函数是公共的,从外部调用,或者从外部
代码调用到状态机对象。系统中的任何线程或任务都可以生成外部事件。如果外部事件函数调用导致状态转换发生,则状态将
在调用方的控制线程内同步执行。另一方面,内部事件是由状态机本身在状态执行期间自行生成的。
典型的场景由生成的外部事件组成,该事件同样可以归结为模块的公共接口中的函数调用。根据正在生成的事件和状态机的当
前状态,执行查找以确定是否需要转换。如果是这样,状态机将转换到新状态,并执行该状态的代码。在状态函数的末尾,执
行检查以确定是否生成了内部事件。如果是这样,则执行另一个转换,并且新的状态有机会执行。此过程将继续进行,直到状
态机不再生成内部事件,此时原始外部事件函数调用将返回。外部事件和所有内部事件(如果有的话)在调用者的控制线程中执
行。
一旦外部事件启动状态机执行,它不能被另一个外部事件中断,直到外部事件和所有内部事件已经完成执行,如果使用锁。这
个运行到完成模型为状态转换提供了一个多线程安全的环境。可以在状态机引擎中使用信号量或互斥量来阻止可能同时访问同
一状态机实例的其他线程。见源代码函数_SM_ExternalEvent()关于锁的位置的注释。
事件数据事件数据
生成事件时,它可以选择附加事件数据,以便在执行过程中由状态函数使用。事件数据是一个const或者不是-const 指向任何
内置或用户定义的数据类型的指针。
一旦状态完成执行,事件数据就被认为用完了,必须删除。因此,发送到状态机的任何事件数据都必须通过SM_XAlloc()。状
态机引擎自动释放分配的事件数据。SM_XFree().
状态转变状态转变
当生成外部事件时,执行查找以确定状态转换操作过程。事件有三种可能的结果:新状态、忽略事件或不能发生。新状态会导
致转换到允许执行的新状态。转换到现有状态也是可能的,这意味着当前状态被重新执行。对于被忽略的事件,不执行任何状
态。但是,事件数据(如果有的话)将被删除。最后一种不可能发生的可能性是保留在事件在状态机的当前状态下无效的情况下
使用的。如果发生这种情况,软件就会出现故障。
在此实现中,执行验证转换查找不需要内部事件。假设状态转换是有效的。您可以检查有效的内部和外部事件转换,但实际
上,这只会占用更多的存储空间,并且只会产生很少的好处。验证转换的真正需要在于异步的外部事件,在这些事件中,客户
端可能导致事件在不适当的时间发生。一旦状态机执行,它就不能被中断。它处于私有实现的控制之下,因此没有必要进行转
换检查。这使设计人员可以自由地通过内部事件更改状态,而无需更新转换表。
状态机模块状态机模块
状态机源代码包含在_StateMachine.c_和_StateMachine.h_档案。下面的代码显示了部分标题。这个StateMachine 报头包含
各种预处理器多行宏,以简化状态机的实现。
enum { EVENT_IGNORED = 0xFE, CANNOT_HAPPEN = 0xFF };
typedef void NoEventData;
// State machine constant data
typedef struct
{
const CHAR* name;
const BYTE maxStates;
const struct SM_StateStruct* stateMap;
const struct SM_StateStructEx* stateMapEx;
} SM_StateMachineConst;
// State machine instance data
typedef struct
{
const CHAR* name;
void* pInstance;
BYTE newState;
BYTE currentState;
BOOL eventGenerated;
void* pEventData;
} SM_StateMachine;
// Generic state function signatures
typedef void (*SM_StateFunc)(SM_StateMachine* self, void* pEventData);
typedef BOOL (*SM_GuardFunc)(SM_StateMachine* self, void* pEventData);
typedef void (*SM_EntryFunc)(SM_StateMachine* self, void* pEventData);
typedef void (*SM_ExitFunc)(SM_StateMachine* self);
typedef struct SM_StateStruct
{
SM_StateFunc pStateFunc;
} SM_StateStruct;
typedef struct SM_StateStructEx
{
SM_StateFunc pStateFunc;
SM_GuardFunc pGuardFunc;
SM_EntryFunc pEntryFunc;
SM_ExitFunc pExitFunc;
} SM_StateStructEx;
// Public functions
#define SM_Event(_smName_, _eventFunc_, _eventData_)
_eventFunc_(&_smName_##Obj, _eventData_)
// Protected functions
#define SM_InternalEvent(_newState_, _eventData_)
_SM_InternalEvent(self, _newState_, _eventData_)
#define SM_GetInstance(_instance_)
(_instance_*)(self->pInstance);
// Private functions
void _SM_ExternalEvent(SM_StateMachine* self,
const SM_StateMachineConst* selfConst, BYTE newState, void* pEventData);
void _SM_InternalEvent(SM_StateMachine* self, BYTE newState, void* pEventData);
void _SM_StateEngine(SM_StateMachine* self, const SM_StateMachineConst* selfConst);
void _SM_StateEngineEx(SM_StateMachine* self, const SM_StateMachineConst* selfConst);
剩余10页未读,继续阅读
weixin_38573171
- 粉丝: 7
- 资源: 945
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- c++校园超市商品信息管理系统课程设计说明书(含源代码) (2).pdf
- 建筑供配电系统相关课件.pptx
- 企业管理规章制度及管理模式.doc
- vb打开摄像头.doc
- 云计算-可信计算中认证协议改进方案.pdf
- [详细完整版]单片机编程4.ppt
- c语言常用算法.pdf
- c++经典程序代码大全.pdf
- 单片机数字时钟资料.doc
- 11项目管理前沿1.0.pptx
- 基于ssm的“魅力”繁峙宣传网站的设计与实现论文.doc
- 智慧交通综合解决方案.pptx
- 建筑防潮设计-PowerPointPresentati.pptx
- SPC统计过程控制程序.pptx
- SPC统计方法基础知识.pptx
- MW全能培训汽轮机调节保安系统PPT教学课件.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0