Linux有限状态机FSM的理解与实现

2019-01-16 23:43:19王振洲

当然使用函数指针实现的FSM的过程还是比较费时费力,但是这一切都是值得的,因为当你的程序规模大时候,基于这种表结构的状态机,维护程序起来也是得心应手。

下面给出一个使用函数指针实现的FSM的框架:

我们还是以“小明的一天”为例设计出该FSM。

先给出该FSM的状态转移图:

下面讲解关键部分代码实现

首先我们定义出小明一天的活动状态

//比如我们定义了小明一天的状态如下 enum { GET_UP, GO_TO_SCHOOL, HAVE_LUNCH, DO_HOMEWORK, SLEEP, };

我们也定义出会发生的事件

enum { EVENT1 = 1, EVENT2, EVENT3, };

定义状态表的数据结构

typedef struct FsmTable_s { int event; //事件 int CurState; //当前状态 void (*eventActFun)(); //函数指针 int NextState; //下一个状态 }FsmTable_t;

接下来定义出最重要FSM的状态表,我们整个FSM就是根据这个定义好的表来运转的。

FsmTable_t XiaoMingTable[] = { //{到来的事件,当前的状态,将要要执行的函数,下一个状态} { EVENT1, SLEEP, GetUp, GET_UP }, { EVENT2, GET_UP, Go2School, GO_TO_SCHOOL }, { EVENT3, GO_TO_SCHOOL, HaveLunch, HAVE_LUNCH }, { EVENT1, HAVE_LUNCH, DoHomework, DO_HOMEWORK }, { EVENT2, DO_HOMEWORK, Go2Bed, SLEEP }, //add your codes here };

状态机的注册、状态转移、事件处理的动作实现

/*状态机注册*/ void FSM_Regist(FSM_t* pFsm, FsmTable_t* pTable) { pFsm->FsmTable = pTable; } /*状态迁移*/ void FSM_StateTransfer(FSM_t* pFsm, int state) { pFsm->curState = state; } /*事件处理*/ void FSM_EventHandle(FSM_t* pFsm, int event) { FsmTable_t* pActTable = pFsm->FsmTable; void (*eventActFun)() = NULL; //函数指针初始化为空 int NextState; int CurState = pFsm->curState; int flag = 0; //标识是否满足条件 int i; /*获取当前动作函数*/ for (i = 0; i<g_max_num; i++) { //当且仅当当前状态下来个指定的事件,我才执行它 if (event == pActTable[i].event && CurState == pActTable[i].CurState) { flag = 1; eventActFun = pActTable[i].eventActFun; NextState = pActTable[i].NextState; break; } } if (flag) //如果满足条件了 { /*动作执行*/ if (eventActFun) { eventActFun(); } //跳转到下一个状态 FSM_StateTransfer(pFsm, NextState); } else { // do nothing } }

主函数我们这样写,然后观察状态机的运转情况

int main() { FSM_t fsm; InitFsm(&fsm); int event = EVENT1; //小明的一天,周而复始的一天又一天,进行着相同的活动 while (1) { printf("event %d is coming...n", event); FSM_EventHandle(&fsm, event); printf("fsm current state %dn", fsm.curState); test(&event); sleep(1); //休眠1秒,方便观察 } return 0; }