有限狀態機FSM

有限狀態機(Finite-state machine)又稱有限狀態自動機,是表示有限個狀態以及在這些狀態之間的轉移和動做等行爲的數學模型。經常使用與:正則表達式引擎,編譯器的詞法和語法分析,遊戲設計,網絡協議,企業應用中等方面。linux

狀態機可概括爲4個要素,即現態、條件、動做、次態。這樣的概括,主要是出於對狀態機的內在因果關係的考慮。
「現態」和「條件」是因,「動做」和「次態」是果。
1. 現態:是指當前所處的狀態。
2. 條件:又稱爲「事件」,當一個條件被知足,將會觸發一個動做,或者執行一次狀態的遷移。
3. 動做:條件知足後執行的動做。動做執行完畢後,能夠遷移到新的狀態,也能夠仍舊保持原狀態。動做不是必需的,當條件知足後,也能夠不執行任何動做,直接遷移到新狀態 。
4. 次態:條件知足後要遷往的新狀態。「次態」是相對於「現態」而言的,「次態」一旦被激活,就轉變成新的「現態」了。git

有限狀態機 FSM 實現github

用while{switch/case}(推薦可讀性高) 或 if/else 實現,簡單粗暴,適合簡單的小型狀態機;
用設計模式中的 state pattern,把複雜判斷的邏輯簡化,利於組織代碼;
用狀態表設計,創建狀態表和動做查詢表,根據狀態表、事件、動做表定位相應的動做處理函數,執行完成後再進行狀態的切換; 正則表達式

 

函數指針實現的FSM的實例windows

// https://github.com/AstarLight/FSM-framework/blob/master/main.c
#include <stdio.h>
//#include <windows.h> //windows
#include <unistd.h>  //linux

//好比咱們定義了小明一天的狀態以下
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;


typedef struct FSM_s
{
    FsmTable_t* FsmTable;   //指向的狀態表
    int curState;  //FSM當前所處的狀態

}FSM_t;


int g_max_num;  //狀態表裏含有的狀態個數



void GetUp()
{
    // do something
    printf("xiao ming gets up!\n");

}

void Go2School()
{
    // do something
    printf("xiao ming goes to school!\n");
}

void HaveLunch()
{
    // do something
    printf("xiao ming has lunch!\n");
}

void DoHomework()
{
    // do something
    printf("xiao ming does homework!\n");
}

void Go2Bed()
{
    // do something
    printf("xiao ming goes to bed!\n");
}

/*狀態機註冊*/
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; //標識是否知足條件

    /*獲取當前動做函數*/
    for (int 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
    }
}

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
};

//初始化FSM
void InitFsm(FSM_t* pFsm)
{
    g_max_num = sizeof(XiaoMingTable) / sizeof(FsmTable_t);
    pFsm->curState = SLEEP;
    FSM_Regist(pFsm, XiaoMingTable);
}


//測試用的
void test(int *event)
{
    if (*event == 3)
    {
        *event = 1;
    }
    else
    {
        (*event)++;
    }

}


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 %d\n", fsm.curState);
        test(&event);
        sleep(1);  //休眠1秒,方便觀察
    }

    return 0;
}
相關文章
相關標籤/搜索