有限狀態機(FSM)的設計與實現(二)


分層狀態機的設計:
對於狀態較多的狀態機,通常的設計會維護一個龐大的二維矩陣,所有狀態耦合在一起,這往往導致維護困難,由於可能存在許多公共的特性,也會導致許多狀態具有相同的處理函數。針對這些問題我們可以通過設計分層狀態機來解決,主要的思想就是根據不同的功能模塊設計出多個狀態機,各個狀態機分布在不同的層次上。上層狀態機調用下層狀態機時,上層狀態機入棧,下層狀態機變為當前處理狀態機。通常我們使用堆棧來保存當前狀態機的上層狀態機信息。

下圖描述一個分層狀態機設計實現:


如上圖所示,假設L1為上層狀態機,L1狀態機在L1_STATE2中可以通過L1L2_EVENT1事件觸發進入L2狀態機,L2狀態機在L2_STATE2中通過L1L2_EVENT2事件觸發返回L1狀態機,L1和L2各自維護自己的狀態表。

數據結構:

struct FSM_S
{
    int curState;                        //當前狀態機狀態
    int curFsmTableSize;                 //當前狀態機查詢表大小
    STATE_TABLE_T* curFsmTable;          //當前狀態機查詢表
    FSM_STACK_T stack[MAX_FSM_STACK_DEP];//狀態機堆棧
    int curStackTop;                     //棧頂
    FSM_REGIST_T registFsm[MAX_FSM_NUM]; //注冊狀態機
    int registFsmNum;                    //注冊狀態機個數
};

1:通過堆棧數據結構維護上層狀態機信息。

2:保存所有可以注冊狀態機信息。

3:記錄當前運行狀態機信息。

主要接口:

void FSM_Init(FSM_T* pFsm);
void FSM_Regist(FSM_T* pFsm,STATE_TABLE_S* pStateTable,int FsmId,int curFsmTableSize);
void FSM_Begin(FSM_T* pFsm,int FsmId);
void FSM_MoveState(FSM_T* pFsm,int state);
void FSM_EventHandle(FSM_T* pFsm,int event);
void FSM_Push(FSM_T* pFsm);
void FSM_Pop(FSM_T* pFsm);

1:FSM_Regist 對所有的狀態機信息進行注冊

void FSM_Regist(FSM_T* pFsm,STATE_TABLE_S* pStateTable,int FsmId, int curFsmTableSize)
{
    pFsm->registFsm[pFsm->registFsmNum].fsmId = FsmId;
    pFsm->registFsm[pFsm->registFsmNum].FsmTable = pStateTable;
    pFsm->registFsm[pFsm->registFsmNum].fsmTableSize = curFsmTableSize;

    pFsm->registFsmNum++;
    return;
}

2:FSM_Begin 用於開始一個新的狀態機流程,切換狀態表信息。

void FSM_Begin(FSM_T* pFsm,int FsmId)
{
    for(int i=0;i<pFsm->registFsmNum;i++)
    {
        if(FsmId == pFsm->registFsm[i].fsmId)
        {
            pFsm->curFsmTable = pFsm->registFsm[i].FsmTable;
            pFsm->curFsmTableSize = pFsm->registFsm[i].fsmTableSize;
            break;
        }
    }
    return;
}

3:FSM_Push/FSM_Pop 用於狀態機切換的出入堆棧操作。

void FSM_Push(FSM_T* pFsm)
{
    if(pFsm->curStackTop < MAX_FSM_STACK_DEP)
    {
        pFsm->curStackTop++;
        pFsm->stack[pFsm->curStackTop].state     = pFsm->curState;
        pFsm->stack[pFsm->curStackTop].pFsmTable = pFsm->curFsmTable;
        pFsm->stack[pFsm->curStackTop].fsmTableSize = pFsm->curFsmTableSize;
    }

    return;
}

void FSM_Pop(FSM_T* pFsm)
{
    if(pFsm->curStackTop > -1)
    {
        pFsm->curState   = pFsm->stack[pFsm->curStackTop].state;
        pFsm->curFsmTable = pFsm->stack[pFsm->curStackTop].pFsmTable;
        pFsm->curFsmTableSize = pFsm->stack[pFsm->curStackTop].fsmTableSize;
        pFsm->curStackTop--;
    }

    return;
}

 接口的使用:

/*L1 狀態機定義*/
ACT_TABLE_T L1state1ActTable[] = {
    {L1_EVENT1,L1state1_Event1Fun},
    {L1_EVENT3,L1state1_Event3Fun},
};
ACT_TABLE_T L1state2ActTable[] = {
    {L1_EVENT2,L1state2_Event2Fun},
    {L1_L2_EVENT1,L1state2_L1L2EventFun},
};
STATE_TABLE_T L1FsmTable[] = {
    {L1_STATE1,sizeof(L1state1ActTable)/sizeof(ACT_TABLE_T),L1state1ActTable},
    {L1_STATE2,sizeof(L1state2ActTable)/sizeof(ACT_TABLE_T),L1state2ActTable},
};
/*L2 狀態機定義*/
ACT_TABLE_T L2state1ActTable[] = {
    {L2_EVENT1,L2state1_L2Event1Fun},
};
ACT_TABLE_T L2state2ActTable[] = {
    {L1_L2_EVENT2,L2state2_L1L2EvenFun},
};
STATE_TABLE_T L2FsmTable[] = {
    {L2_STATE1,sizeof(L2state1ActTable)/sizeof(ACT_TABLE_T),L2state1ActTable},
    {L2_STATE2,sizeof(L2state2ActTable)/sizeof(ACT_TABLE_T),L2state2ActTable},
};

int main(int argc, _TCHAR* argv[])
{
    FSM_T pFsm;
FSM_Init(
&pFsm); /*狀態機注冊*/ FSM_Regist(&pFsm,L1FsmTable,FSM_L1,sizeof(L1FsmTable)/sizeof(STATE_TABLE_T)); FSM_Regist(&pFsm,L2FsmTable,FSM_L2,sizeof(L2FsmTable)/sizeof(STATE_TABLE_T)); /*開始L1狀態機*/ FSM_Begin(&pFsm,FSM_L1); FSM_MoveState(&pFsm,L1_STATE1); FSM_EventHandle(&pFsm,L1_EVENT1); /*push 狀態機*/ FSM_EventHandle(&pFsm,L1_L2_EVENT1); /*L2狀態機處理*/ FSM_EventHandle(&pFsm,L2_EVENT1); /*pop 狀態機*/ FSM_EventHandle(&pFsm,L1_L2_EVENT2); /*L1狀態機處理*/ FSM_EventHandle(&pFsm,L1_EVENT2); return 0; }

1:首先通過FSM_Regist注冊所有的狀態機。

2:FSM_EventHandle(&pFsm,L1_L2_EVENT1)中的動作處理函數中進行壓棧操作同時進入L2狀態機。

void L1state2_L1L2EventFun(void* pFsm)
{
    FSM_Push((FSM_T*)pFsm);
    FSM_Begin((FSM_T*)pFsm,FSM_L2);
    FSM_MoveState((FSM_T*)pFsm,L2_STATE1);

    return;
}

3:FSM_EventHandle(&pFsm,L1_L2_EVENT2)中的動作處理函數中進行出棧操作返回到L1狀態機。

void L2state2_L1L2EvenFun(void* pFsm)
{
    FSM_Pop((FSM_T*)pFsm);

    return;
}

 結論:

通過分層狀態機的設計,各個功能實體維護自身的強相關的一套狀態機,可以有效的減小狀態機的復雜度,通過構建公共流程狀態機,可以減小規模。綜上所述:在針對規模較大、流程復雜的狀態機設計,我們考慮使用分層的設計方法。

轉載請注明原始出處:http://www.cnblogs.com/chencheng/archive/2012/06/28/2564336.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM