有限状态机(finite state machine)简称FSM,表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用。FSM是一种逻辑单元内部的一种高效编程方法,在服务器编程中,服务器可以根据不同状态或者消息类型进行相应的处理逻辑,使得程序逻辑清晰易懂。
状态机实现的方式有多种,下面讲述三种.
使用if/else if语句实现的FSM
使用if/else if语句是实现的FSM最简单最易懂的方法,我们只需要通过大量的if /else if语句来判断状态值来执行相应的逻辑处理。
看看下面的例子:
#include <stdio.h>
enum year_state
{
SPRING,
SUMMER,
AUTUMN,
WINTER
};
void spring_thing()
{
printf("hello spring\n");
}
void summer_thing()
{
printf("hello summer\n");
}
void autumn_thing()
{
printf("hello autumn\n");
}
void winter_thing()
{
printf("hello winter\n");
}
int main()
{
int state = SPRING;
while (1)
{
if (state == SPRING)
{
spring_thing();//相应的处理
state = SUMMER;//状态改变
}
else if (state == SUMMER)
{
summer_thing();
state = AUTUMN;
}
else if (state == AUTUMN)
{
autumn_thing();
state = WINTER;
}
else if (state == WINTER)
{
winter_thing();
state = SPRING;
}
sleep(1);
}
return 0;
}
简单易懂,这里实现了四季的更替,因为只有四种状态,所以逻辑清楚,试想如果有个几十种状态,我们的if else将会变得十分之长,维护起来很麻烦,删减和添加状态变得不方便.但是通过这个例子我们认识到状态机的内涵.
如下图:
在状态1时,遇到一个事件,此刻发生状态转换,一般在状态转换前,先要进行事件的处理,然后改变状态位.然后进入状态2,以此类推.
使用switch case
这种做法和if else类似,结构上更清楚一些,代码如下:
int main()
{
int state = SPRING;
while (1)
{
switch(state){
case SPRING:
spring_thing();
state = SUMMER;
break;
case SUMMER:
summer_thing();
state = AUTUMN;
break;
case AUTUMN:
autumn_thing();
state = WINTER;
break;
case WINTER:
winter_thing();
state = SPRING;
break;
default:
break;
}
sleep(1);
}
return 0;
}
函数指针实现FSM
使用函数指针实现FSM的思路:建立相应的状态表和动作查询表,根据状态表、事件、动作表定位相应的动作处理函数,执行完成后再进行状态的切换。
当然使用函数指针实现的FSM的过程还是比较费时费力,但是这一切都是值得的,因为当你的程序规模大时候,基于这种表结构的状态机,维护程序起来也是得心应手。
首先我们画出这个表
代码:
#ifndef _FSM_H_
#define _FSM_H_
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
//===============
/*状态号*/
typedef enum {
walk_state = 1,
talk_state,
fly_state,
run_state,
jump_state
}FSM_STATE,*FSM_STATE_P;
/*事件*/
typedef enum {
walk_event = 1,
talk_event,
fly_event,
run_event,
jump_event
}FSM_EVENT, *FSM_EVENT_P;
typedef struct FsmTable_s
{
uint8_t event; /* 触发事件名字 */
uint8_t CurState; /* 当前状态 */
void (*eventActFun)(void *); /* 动作函数 */
uint8_t NextState; /* 跳转状态 */
}FsmTable_T,*FsmTable_T_P;
typedef struct FSM_s
{
FsmTable_T *FsmTable; /* 状态迁移表 */
uint8_t curState; /* 状态机当前状态 */
uint8_t stuMaxNum; /* 状态机状态迁移数量 */
}FSM_T, *FSM_T_P ;
/*********************************************************************************
使用方法:1.创建FSM_T对象;
2.创建FsmTable_T表;
3.调用FSM_Init()初始化;
4.程序轮询FSM_EventHandle()运行状态机。
*********************************************************************************/
void FSM_Regist(FSM_T *pFsm, FsmTable_T *pTable, uint8_t stuMaxNum, uint8_t curState);
void FSM_EventHandle(FSM_T *pFsm, uint8_t event, void *parm);
#endif
#include "fsm.h"
/*==================================================================
* Function : FSM_StateTransfer
* Description : 状态转换
* Input Para :
* Output Para :
* Return Value:
==================================================================*/
static void FSM_StateTransfer(FSM_T *pFsm, uint8_t state)
{
pFsm->curState = state;
}
/*==================================================================
* Function : FSM_EventHandle
* Description : 状态机处理函数
* Input Para : pFsm状态机对象, event触发事件, parm动作执行参数
* Output Para :
* Return Value:
==================================================================*/
void FSM_EventHandle(FSM_T *pFsm, uint8_t event, void *parm)
{
/*创建一个状态对象指向当前的状态*/
FsmTable_T *pAcTable = pFsm->FsmTable;
/*当前状态要执行的事件函数*/
void (*eventActFun)(void *) = NULL;
uint8_t NextState;
/*获取当前状态号*/
uint8_t CurState = pFsm->curState;
uint8_t flag = 0;
/*遍历状态链表*/
for (uint8_t i = 0; i < pFsm->stuMaxNum; i++)
{
/*当且仅当当前状态下来个事件才执行*/
if (event == pAcTable[i].event && CurState == pAcTable[i].CurState)
{
/*允许执行状态事件*/
flag = 1;
/*获取当前状态事件执行函数*/
eventActFun = pAcTable[i].eventActFun;
/*获取下一个状态事件号*/
NextState = pAcTable[i].NextState;
break;
}
}
/*开始执行状态事件*/
if (flag)
{
/*如果当前状态事件有需要执行的函数,就执行*/
if (eventActFun != NULL)
{
eventActFun(parm); // 执行相应动作
}
/*状态转换*/
FSM_StateTransfer(pFsm, NextState);
}
else
{
/*do nothing*/
}
}
/*==================================================================
* Function : FSM_Init
* Description : 状态机注册
* Input Para : pFsm状态机对象,pTable状态迁移表,stuMaxNum迁移表数量
* curState当前状态
* Output Para :
* Return Value:
==================================================================*/
void FSM_Regist(FSM_T *pFsm, FsmTable_T *pTable, uint8_t stuMaxNum, uint8_t curState)
{
pFsm->FsmTable = pTable;
pFsm->curState = curState;
pFsm->stuMaxNum = stuMaxNum;
}
//====================函数声明====================================
void walk(void *);
void talk(void *);
void fly(void *);
void run(void *);
void jump(void *);
//==========================================================
int main(void )
{
/*创建FSM_T对象*/
FSM_T fsm = {0};
FSM_T_P fsm_p = &fsm;
/*创建FsmTable_T表*/
FsmTable_T fsm_table[5] = {
{walk_event , walk_state , walk, talk_state},
{talk_event , talk_state , talk, run_state},
{ fly_event , fly_state ,fly , jump_state},
{run_event ,run_state ,run,fly_state},
{jump_event,jump_state,jump,walk_state}
};
char i = 1;
/*FSM_Init()初始化*/
FSM_Regist(fsm_p, fsm_table,5, walk_state);
int EVENT = 0;
while(1)
{
/*轮询运行状态机*/
FSM_EventHandle(fsm_p,EVENT,&i);
EVENT++;
if(EVENT>5) EVENT = 1;
}
return 0;
}
//========================函数实现==================================
void walk(void * t)
{
printf("我正在走\r\n");
}
void talk(void * t)
{
printf("我正在讲话\r\n");
}
void fly(void * t)
{
printf("我正在飞机上\r\n");
}
void run(void * t )
{
printf("我正在跑步\r\n");
}
void jump(void * t)
{
printf("我正在跳高\r\n");
}
//===========================================================
运行:
参考文章链接:https://www.jianshu.com/p/917c0fb8778b?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation