FSM设计和实现2

分层状态机的设计:
对于状态较多的状态机,通常的设计会维护一个庞大的二维矩阵,所有状态耦合在一起,这往往导致维护困难,由于可能存在许多公共的特性,也会导致许多状态具有相同的处理函数。针对这些问题我们可以通过设计分层状态机来解决,主要的思想就是根据不同的功能模块设计出多个状态机,各个状态机分布在不同的层次上。上层状态机调用下层状态机时,上层状态机入栈,下层状态机变为当前处理状态机。通常我们使用堆栈来保存当前状态机的上层状态机信息。

下图描述一个分层状态机设计实现:


如上图所示,假设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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值