状态机-概述
有限状态机(finite state machine)简称FSM,表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用。FSM是一种逻辑单元内部的一种高效编程方法,在服务器编程中,服务器可以根据不同状态或者消息类型进行相应的处理逻辑,使得程序逻辑清晰易懂。
实现方法
使用if/else if语句实现的FSM
使用if/else if语句是实现的FSM最简单最易懂的方法,我们只需要通过大量的if /else if语句来判断状态值来执行相应的逻辑处理。
看看下面的例子:
#include <stdio.h>
//
// ┏┛ ┻━━━━━┛ ┻┓
// ┃ ┃
// ┃ ━ ┃
// ┃ ┳┛ ┗┳ ┃
// ┃ ┃
// ┃ ┻ ┃
// ┃ ┃
// ┗━┓ ┏━━━┛
// ┃ ┃ 神兽保佑
// ┃ ┃ 代码无BUG!
// ┃ ┗━━━━━━━━━┓
// ┃ ┣┓
// ┃ ┏┛
// ┗━┓ ┓ ┏━━━┳ ┓ ┏━┛
// ┃ ┫ ┫ ┃ ┫ ┫
// ┗━┻━┛ ┗━┻━┛
enum Year_State
{
SPRING,
SUMMER,
AUTUMN,
WINTER
};
void do_spring()
{
printf("---------%s-------------\n",__FUNCTION__);
}
void do_summber()
{
printf("---------%s-------------\n",__FUNCTION__);
}
void do_autumn()
{
printf("---------%s-------------\n",__FUNCTION__);
}
void do_winter()
{
printf("---------%s-------------\n",__FUNCTION__);
}
int main(int argc, const char *argv[])
{
int state = SPRING;
while (1)
{
if (state == SPRING)
{
do_spring();//相应的处理
state = SUMMER;//状态改变
}
else if (state == SUMMER)
{
do_summber();
state = AUTUMN;
}
else if (state == AUTUMN)
{
do_autumn();
state = WINTER;
}
else if (state == WINTER)
{
do_winter();
state = SPRING;
}
sleep(1);
}
return 0;
}
简单易懂,这里实现了四季的更替,因为只有四种状态,所以逻辑清楚,试想如果有个几十种状态,我们的if else将会变得十分之长,维护起来很麻烦,删减和添加状态变得不方便.但是通过这个例子我们认识到状态机的内涵.
如下图:
在状态1时,遇到一个事件,此刻发生状态转换,一般在状态转换前,先要进行事件的处理,然后改变状态位.然后进入状态2,以此类推.
使用switch case
这种做法和if else类似,结构上更清楚一些,代码如下:
int main(int argc, const char *argv[])
{
int state = SPRING;
while (1)
{
switch(state)
{
case SPRING:
do_spring();
state = SUMMER;//进入下一个状态
break;
case SUMMER:
do_summber();
state = AUTUMN;
break;
case AUTUMN:
do_autumn();
state = WINTER;
break;
case WINTER:
do_winter();
state = SPRING;
break;
default:
break;
}
sleep(1);
}
return 0;
}
函数指针实现FSM
使用函数指针实现FSM的思路:建立相应的状态表和动作查询表,根据状态表、事件、动作表定位相应的动作处理函数,执行完成后再进行状态的切换。
当然使用函数指针实现的FSM的过程还是比较费时费力,但是这一切都是值得的,因为当你的程序规模大时候,基于这种表结构的状态机,维护程序起来也是得心应手。
首先我们画出这个表
#include <stdio.h>
//
// ┏┛ ┻━━━━━┛ ┻┓
// ┃ ┃
// ┃ ━ ┃
// ┃ ┳┛ ┗┳ ┃
// ┃ ┃
// ┃ ┻ ┃
// ┃ ┃
// ┗━┓ ┏━━━┛
// ┃ ┃ 神兽保佑
// ┃ ┃ 代码无BUG!
// ┃ ┗━━━━━━━━━┓
// ┃ ┣┓
// ┃ ┏┛
// ┗━┓ ┓ ┏━━━┳ ┓ ┏━┛
// ┃ ┫ ┫ ┃ ┫ ┫
// ┗━┻━┛ ┗━┻━┛
//定义状态数据的枚举类型
typedef enum Year_State
{
SPRING = 1,
SUMMER,
AUTUMN,
WINTER
}YEAR_START_E;
//定义事件的枚举类型
typedef enum Year_Event
{
SPRING_EVENT = 1,
SUMMER_EVENT,
AUTUMN_EVENT,
WINTER_EVENT,
}YEAR_EVENT_T;
//定义状态表的数据类型
typedef struct FsmTable_s
{
int Event; //事件
int CurentState; //当前状态
void (*EventActFun)(); //函数指针
int NextState; //下一个状态
}FsmTable_T;
//定义处理函数及建立状态表
void do_spring()
{
printf("---------%s-------------\n",__FUNCTION__);
}
void do_summber()
{
printf("---------%s-------------\n",__FUNCTION__);
}
void do_autumn()
{
printf("---------%s-------------\n",__FUNCTION__);
}
void do_winter()
{
printf("---------%s-------------\n",__FUNCTION__);
}
FsmTable_T year_table[] =
{
//{到来的事件,当前的状态,将要要执行的函数,下一个状态}
{ SPRING_EVENT, SPRING, do_spring, SUMMER },
{ SUMMER_EVENT, SUMMER, do_summber, AUTUMN },
{ AUTUMN_EVENT, AUTUMN, do_autumn, WINTER },
{ WINTER_EVENT, WINTER, do_winter, SPRING }
//add your codes here
};
typedef struct FSM_s{
int CurState;//当前状态
FsmTable_T * pFsmTable;//状态表
int size;//表的项数
}FSM_T;
/*状态机注册,给它一个状态表*/
void FSM_Regist(FSM_T* pFsm, FsmTable_T* pTable)
{
pFsm->pFsmTable = pTable;
}
/*状态迁移*/
void FSM_StateTransfer(FSM_T* pFsm, int state)
{
pFsm->CurState = state;
}
/*事件处理*/
void FSM_EventHandle(FSM_T* pFsm, int event)
{
FsmTable_T* pActTable = pFsm->pFsmTable;
void (*eventActFun)() = NULL; //函数指针初始化为空
int NextState;
int CurState = pFsm->CurState;
int g_max_num = pFsm->size;
int flag = 0; //标识是否满足条件
int i;
/*获取当前动作函数*/
for (i = 0; i<g_max_num; i++)
{
//当且仅当当前状态下来个指定的事件,我才执行它
if (event == pActTable[i].Event && CurState == pActTable[i].CurentState)
{
flag = 1;
eventActFun = pActTable[i].EventActFun;
NextState = pActTable[i].NextState;
break;
}
}
if (flag) //如果满足条件了
{
/*动作执行*/
if (eventActFun)
{
eventActFun();
}
//跳转到下一个状态
FSM_StateTransfer(pFsm, NextState);
}
else
{
printf("there is no match\n");
}
}
int main(int argc, const char *argv[])
{
FSM_T year_fsm;
FSM_Regist(&year_fsm,year_table);
year_fsm.CurState = SPRING;
year_fsm.size = sizeof(year_table)/sizeof(FsmTable_T);
printf("\n-------1--init spring------\n");
printf("state:%d\n",year_fsm.CurState);
printf("\n-------2--spring->summer------\n");
FSM_EventHandle(&year_fsm,SPRING_EVENT);
printf("state:%d\n",year_fsm.CurState);
printf("\n-------3--summer->autumn------\n");
FSM_EventHandle(&year_fsm,SUMMER_EVENT);
printf("state:%d\n",year_fsm.CurState);
printf("\n-------4--autumn->winter------\n");
FSM_EventHandle(&year_fsm,AUTUMN_EVENT);
printf("state:%d\n",year_fsm.CurState);
printf("\n-------5--winter->spring------\n");
FSM_EventHandle(&year_fsm,WINTER_EVENT);
printf("state:%d\n",year_fsm.CurState);
printf("\n-------6--receive SUMMER_EVENT not SPRING_EVENT------\n");
FSM_EventHandle(&year_fsm,SUMMER_EVENT);
printf("state:%d\n",year_fsm.CurState);
return 0;
}
测试结果:
-------1--init spring------
state:1
-------2--spring->summer------
---------do_spring-------------
state:2
-------3--summer->autumn------
---------do_summber-------------
state:3
-------4--autumn->winter------
---------do_autumn-------------
state:4
-------5--winter->spring------
---------do_winter-------------
state:1
-------6--receive SUMMER_EVENT not SPRING_EVENT------
there is no match
state:1
参考
来源:CSDN
作者:奋斗_2019
链接:https://blog.csdn.net/Set_Mode/article/details/95059998