有限狀態(tài)機(jī)(finite state machine)簡稱FSM付呕,表示有限個狀態(tài)及在這些狀態(tài)之間的轉(zhuǎn)移和動作等行為的數(shù)學(xué)模型计福,在計算機(jī)領(lǐng)域有著廣泛的應(yīng)用。FSM是一種邏輯單元內(nèi)部的一種高效編程方法徽职,在服務(wù)器編程中象颖,服務(wù)器可以根據(jù)不同狀態(tài)或者消息類型進(jìn)行相應(yīng)的處理邏輯,使得程序邏輯清晰易懂姆钉。
狀態(tài)機(jī)實(shí)現(xiàn)的方式有多種力麸,下面講述三種.
1.使用if/else if語句實(shí)現(xiàn)的FSM
使用if/else if語句是實(shí)現(xiàn)的FSM最簡單最易懂的方法,我們只需要通過大量的if /else if語句來判斷狀態(tài)值來執(zhí)行相應(yīng)的邏輯處理育韩。
看看下面的例子:
#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();//相應(yīng)的處理
state = SUMMER;//狀態(tài)改變
}
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;
}
簡單易懂,這里實(shí)現(xiàn)了四季的更替,因?yàn)橹挥兴姆N狀態(tài),所以邏輯清楚,試想如果有個幾十種狀態(tài),我們的if else將會變得十分之長,維護(hù)起來很麻煩,刪減和添加狀態(tài)變得不方便.但是通過這個例子我們認(rèn)識到狀態(tài)機(jī)的內(nèi)涵.
如下圖:
在狀態(tài)1時,遇到一個事件,此刻發(fā)生狀態(tài)轉(zhuǎn)換,一般在狀態(tài)轉(zhuǎn)換前,先要進(jìn)行事件的處理,然后改變狀態(tài)位.然后進(jìn)入狀態(tài)2,以此類推.
2.使用switch case
這種做法和if else類似,結(jié)構(gòu)上更清楚一些,代碼如下:
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;
}
3.函數(shù)指針實(shí)現(xiàn)FSM
使用函數(shù)指針實(shí)現(xiàn)FSM的思路:建立相應(yīng)的狀態(tài)表和動作查詢表,根據(jù)狀態(tài)表闺鲸、事件筋讨、動作表定位相應(yīng)的動作處理函數(shù),執(zhí)行完成后再進(jìn)行狀態(tài)的切換摸恍。
當(dāng)然使用函數(shù)指針實(shí)現(xiàn)的FSM的過程還是比較費(fèi)時費(fèi)力悉罕,但是這一切都是值得的,因?yàn)楫?dāng)你的程序規(guī)模大時候立镶,基于這種表結(jié)構(gòu)的狀態(tài)機(jī)壁袄,維護(hù)程序起來也是得心應(yīng)手。
首先我們畫出這個表
代碼關(guān)鍵部分:
1.定義狀態(tài)數(shù)據(jù)的枚舉類型
enum year_state
{
SPRING = 1,
SUMMER,
AUTUMN,
WINTER
};
2.定義事件的枚舉類型
enum year_event
{
EVENT1 = 1,
EVENT2,
EVENT3,
EVENT4,
};
3.定義狀態(tài)表的數(shù)據(jù)類型
typedef struct FsmTable_s
{
int event; //事件
int CurState; //當(dāng)前狀態(tài)
void (*eventActFun)(); //函數(shù)指針
int NextState; //下一個狀態(tài)
}FsmTable_t;
4.定義處理函數(shù)及建立狀態(tài)表
void spring_thing()
{
printf("this is spring\n");
}
void summer_thing()
{
printf("this is summer\n");
}
void autumn_thing()
{
printf("this is autumn\n");
}
void winter_thing()
{
printf("this is winter\n");
}
FsmTable_t year_table[] =
{
//{到來的事件媚媒,當(dāng)前的狀態(tài)嗜逻,將要要執(zhí)行的函數(shù),下一個狀態(tài)}
{ EVENT1, SPRING, summer_thing, SUMMER },
{ EVENT2, SUMMER, autumn_thing, AUTUMN },
{ EVENT3, AUTUMN, winter_thing, WINTER },
{ EVENT4, WINTER, spring_thing, SPRING },
//add your codes here
};
5.狀態(tài)機(jī)類型,及狀態(tài)機(jī)接口函數(shù)
/*狀態(tài)機(jī)類型*/
typedef struct FSM_s{
int curState;//當(dāng)前狀態(tài)
FsmTable_t * pFsmTable;//狀態(tài)表
int size;//表的項(xiàng)數(shù)
}FSM_t;
/*狀態(tài)機(jī)注冊,給它一個狀態(tài)表*/
void FSM_Regist(FSM_t* pFsm, FsmTable_t* pTable)
{
pFsm->pFsmTable = pTable;
}
/*狀態(tài)遷移*/
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; //函數(shù)指針初始化為空
int NextState;
int CurState = pFsm->curState;
int g_max_num = pFsm->size;
int flag = 0; //標(biāo)識是否滿足條件
int i;
/*獲取當(dāng)前動作函數(shù)*/
for (i = 0; i<g_max_num; i++)
{
//當(dāng)且僅當(dāng)當(dāng)前狀態(tài)下來個指定的事件缭召,我才執(zhí)行它
if (event == pActTable[i].event && CurState == pActTable[i].CurState)
{
flag = 1;
eventActFun = pActTable[i].eventActFun;
NextState = pActTable[i].NextState;
break;
}
}
if (flag) //如果滿足條件了
{
/*動作執(zhí)行*/
if (eventActFun)
{
eventActFun();
}
//跳轉(zhuǎn)到下一個狀態(tài)
FSM_StateTransfer(pFsm, NextState);
}
else
{
printf("there is no match\n");
}
}
測試程序代碼為:
/*state.c*/
#include <stdio.h>
enum year_state{
SPRING = 1,
SUMMER,
AUTUMN,
WINTER
};
enum year_event{
EVENT1 = 1,
EVENT2,
EVENT3,
EVENT4,
};
typedef struct FsmTable_s{
int event; //事件
int CurState; //當(dāng)前狀態(tài)
void (*eventActFun)(); //函數(shù)指針
int NextState; //下一個狀態(tài)
}FsmTable_t;
void spring_thing()
{
printf("this is spring\n");
}
void summer_thing()
{
printf("this is summer\n");
}
void autumn_thing()
{
printf("this is autumn\n");
}
void winter_thing()
{
printf("this is winter\n");
}
FsmTable_t year_table[] =
{
//{到來的事件栈顷,當(dāng)前的狀態(tài)逆日,將要要執(zhí)行的函數(shù),下一個狀態(tài)}
{ EVENT1, SPRING, summer_thing, SUMMER },
{ EVENT2, SUMMER, autumn_thing, AUTUMN },
{ EVENT3, AUTUMN, winter_thing, WINTER },
{ EVENT4, WINTER, spring_thing, SPRING },
//add your codes here
};
typedef struct FSM_s{
int curState;//當(dāng)前狀態(tài)
FsmTable_t * pFsmTable;//狀態(tài)表
int size;//表的項(xiàng)數(shù)
}FSM_t;
/*狀態(tài)機(jī)注冊,給它一個狀態(tài)表*/
void FSM_Regist(FSM_t* pFsm, FsmTable_t* pTable)
{
pFsm->pFsmTable = pTable;
}
/*狀態(tài)遷移*/
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; //函數(shù)指針初始化為空
int NextState;
int CurState = pFsm->curState;
int g_max_num = pFsm->size;
int flag = 0; //標(biāo)識是否滿足條件
int i;
/*獲取當(dāng)前動作函數(shù)*/
for (i = 0; i<g_max_num; i++)
{
//當(dāng)且僅當(dāng)當(dāng)前狀態(tài)下來個指定的事件萄凤,我才執(zhí)行它
if (event == pActTable[i].event && CurState == pActTable[i].CurState)
{
flag = 1;
eventActFun = pActTable[i].eventActFun;
NextState = pActTable[i].NextState;
break;
}
}
if (flag) //如果滿足條件了
{
/*動作執(zhí)行*/
if (eventActFun)
{
eventActFun();
}
//跳轉(zhuǎn)到下一個狀態(tài)
FSM_StateTransfer(pFsm, NextState);
}
else
{
printf("there is no match\n");
}
}
int main()
{
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,EVENT1);
printf("state:%d\n",year_fsm.curState);
printf("\n-------3--summer->autumn------\n");
FSM_EventHandle(&year_fsm,EVENT2);
printf("state:%d\n",year_fsm.curState);
printf("\n-------4--autumn->winter------\n");
FSM_EventHandle(&year_fsm,EVENT3);
printf("state:%d\n",year_fsm.curState);
printf("\n-------5--winter->spring------\n");
FSM_EventHandle(&year_fsm,EVENT4);
printf("state:%d\n",year_fsm.curState);
printf("\n-------6--receive EVENT2 not EVENT1------\n");
FSM_EventHandle(&year_fsm,EVENT2);
printf("state:%d\n",year_fsm.curState);
return 0;
}
結(jié)果為:
-------1--init spring------
state:1
-------2--spring->summer------
this is summer
state:2
-------3--summer->autumn------
this is autumn
state:3
-------4--autumn->winter------
this is winter
state:4
-------5--winter->spring------
this is spring
state:1
-------6--receive EVENT2 not EVENT1------
there is no match
state:1