技術系列之 狀態機(二)

3、狀態機實現
(2)面向過程方式
二、層次狀態機模塊實現。算法

與常規狀態機相比,它的FSM_STATE結構沒有default_func,多了 FSM_STATE_ID parent; FSM_STATE_ID default_child;兩個結構。狀態機初始化的時候能夠指定默認狀態,爲了防止指定的狀態非葉結點,增長fsm_init方法。該狀態機的事件處理算法簡單描述以下:(1)首先在當前狀態以及其祖先狀態的狀態事件表中搜索匹配事件,若是搜索到,保存操做以及目的狀態標識;(2)在old棧中保存當前狀態到根節點的路徑,在new棧中保存目的狀態到根節點的路徑;(3)將old棧中的頂層元素依次與new棧的頂層元素匹配,若是匹配則都出棧,不匹配,中止;(4)當前的old棧中節點即爲該事件致使的退出狀態,從棧低掃描到棧頂,依次執行exit_func;(5)執行之前保存的操做;(6)掃描new棧,從棧頂到棧低依次執行enter_func;(7)最後檢測目的狀態是不是葉節點狀態,否,則依次進入default_child節點,並執行enter_func。模塊實現代碼以下:
#define SINGLE_STATE_MAX_EVENT  10
#define STATE_TREE_DEPTH 
10
typedef  
int  FSM_EVENT_ID;
typedef struct event_param_st
{
    FSM_EVENT_ID id;
    union{
        int i;
    }
data;
}
FSM_EVENT;
typedef  
int  FSM_STATE_ID;
typedef 
void  ( * FSM_FUNC)(FSM_EVENT  * );
typedef struct state_event_st
{
    FSM_FUNC func;
    FSM_EVENT_ID event;
    FSM_STATE_ID state;
}
FSM_STATE_EVENT;
typedef struct state_st
{
    FSM_STATE_ID id;
    char *name;
    FSM_STATE_ID parent;
    FSM_STATE_ID default_child;
    FSM_FUNC enter_func;
    FSM_FUNC exit_func;
    FSM_STATE_EVENT event_table[SINGLE_STATE_MAX_EVENT]; 
}
FSM_STATE;
typedef FSM_STATE STATE_TABLE[];
typedef FSM_STATE 
*  PTR_STATE_TABLE;

#define END_EVENT_ID 
- 1
#define END_STATE_ID 
- 1
#define BEGIN_FSM_STATE_TABLE(state_stable) 
static  STATE_TABLE state_stable = {
#define BEGIN_STATE(id,name,parent,default_child,enter_func,exit_func) {id,name,parent,default_child,enter_func,exit_func,{
#define STATE_EVENT_ITEM(func,event,state) {func,event,state},
#define END_STATE(id) {NULL,END_EVENT_ID,END_STATE_ID}}
}
,
#define END_FSM_STATE_TABLE(state_stable) {END_STATE_ID,NULL,END_STATE_ID,END_STATE_ID,NULL,NULL,NULL}}
;

typedef struct fsm_st
{
    FSM_STATE_ID state_id;
    FSM_FUNC default_func;
    PTR_STATE_TABLE state_tables;
}
FSM;

void  fsm_init(FSM  & fsm)
{
    FSM_STATE *state=&(fsm.state_tables[fsm.state_id]);
    while(state->default_child!=END_STATE_ID)
    {
        state=&(fsm.state_tables[state->default_child]);
        if(state->enter_func)
            state->enter_func(NULL);
    }

    fsm.state_id=state->id;
}

void  fsm_do_event(FSM  & fsm, FSM_EVENT  & event)
{
    FSM_STATE *state;
    FSM_STATE_ID state_id,old_state_id,new_state_id;
    FSM_STATE_ID oldStack[STATE_TREE_DEPTH],newStack[STATE_TREE_DEPTH];
    int old_cur=0,new_cur=0;
    
    bool isMatch=false;
    FSM_FUNC match_func=NULL;
    int i=0;
    state_id=old_state_id=fsm.state_id;
    do
    {
        i=0;
        state=&(fsm.state_tables[state_id]);
        while(state->event_table[i].event!=END_EVENT_ID)
        {
            if(state->event_table[i].event==event.id)
            {
                isMatch=true;
                match_func=state->event_table[i].func;
                new_state_id=state->event_table[i].state;
                break;
            }

            i++;
        }

        if(isMatch==false)
            state_id=state->parent;
        else
            break;
    }
while(state->parent!=END_STATE_ID);
    if(isMatch==false)
    {
        if(fsm.default_func)
            fsm.default_func(&event);
        return;
    }

    if(new_state_id==old_state_id)
    {
        if(match_func)
            match_func(&event);
        return;
    }

    state_id=old_state_id;
    do
    {
        oldStack[old_cur++]=state_id;
        state=&(fsm.state_tables[state_id]);
        state_id=state->parent;
    }
while(state->parent!=END_STATE_ID);
    state_id=new_state_id;
    do
    {
        newStack[new_cur++]=state_id;
        state=&(fsm.state_tables[state_id]);
        state_id=state->parent;
    }
while(state->parent!=END_STATE_ID);
    while(oldStack[old_cur-1]==newStack[new_cur-1])
    {
        old_cur--;
        new_cur--;
    }

    for(i=0;i<old_cur;i++)
    {
        if(fsm.state_tables[oldStack[i]].exit_func)
            fsm.state_tables[oldStack[i]].exit_func(&event);
    }

    if(match_func)
        match_func(&event);
    for(i=new_cur;i>0;i--)
    {
        if(fsm.state_tables[newStack[i-1]].enter_func)
            fsm.state_tables[newStack[i-1]].enter_func(&event);
    }

    state=&(fsm.state_tables[new_state_id]);
    while(state->default_child!=END_STATE_ID)
    {
        state=&(fsm.state_tables[state->default_child]);
        if(state->enter_func)
            state->enter_func(&event);
    }

    fsm.state_id=state->id;
}
使用舉例,僅僅列舉一個狀態表和簡單的狀態機初始化,狀態和事件應該爲enum,當前使用數字,僅爲了舉例,操做的實現不在寫出。
BEGIN_FSM_STATE_TABLE(my_state_table)
    BEGIN_STATE(
0 , " first " ,END_STATE_ID, 2 ,enter_fsm,exit_fsm)
        STATE_EVENT_ITEM(func_fsm,
1 , 1 )
        STATE_EVENT_ITEM(func_fsm,
2 , 2 )
    END_STATE(
0 )
    
    BEGIN_STATE(
1 , " second " , 0 ,END_STATE_ID,enter_fsm,exit_fsm)
        STATE_EVENT_ITEM(func_fsm,
1 , 3 )
        STATE_EVENT_ITEM(func_fsm,
2 , 0 )
    END_STATE(
1 )
    
    BEGIN_STATE(
2 , " third " , 0 , 3 ,enter_fsm,exit_fsm)
        STATE_EVENT_ITEM(func_fsm,
1 , 0 )
        STATE_EVENT_ITEM(func_fsm,
2 , 1 )
    END_STATE(
2 )
    BEGIN_STATE(
3 , " third " , 2 ,END_STATE_ID,enter_fsm,exit_fsm)
        STATE_EVENT_ITEM(func_fsm,
1 , 4 )
        STATE_EVENT_ITEM(func_fsm,
2 , 1 )
    END_STATE(
3 )
    BEGIN_STATE(
4 , " third " , 2 ,END_STATE_ID,enter_fsm,exit_fsm)
        STATE_EVENT_ITEM(func_fsm,
1 , 2 )
        STATE_EVENT_ITEM(func_fsm,
2 , 1 )
    END_STATE(
4 )
END_FSM_STATE_TABLE(my_state_table)

FSM fsm = {0,default_fsm,my_state_table} ;
fsm_init(fsm);
FSM_EVENT event;
event.id
= 1 ;
event.data.i
= 1 ;
fsm_do_event(fsm,event);



後續提綱:
3、狀態機實現
(3)面向對象方式 常規&層次異步

4、狀態機分析
5、狀態機迴路檢測
6、狀態機使用
另介紹boost中同步異步狀態機spa

相關文章
相關標籤/搜索