C语言实现简单有限状态机(FSM)

梦想与她 提交于 2019-11-27 02:23:01

状态机-概述

有限状态机(finite state machine)简称FSM,表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用。FSM是一种逻辑单元内部的一种高效编程方法,在服务器编程中,服务器可以根据不同状态或者消息类型进行相应的处理逻辑,使得程序逻辑清晰易懂。

实现方法

使用if/else if语句实现的FSM

使用if/else if语句是实现的FSM最简单最易懂的方法,我们只需要通过大量的if /else if语句来判断状态值来执行相应的逻辑处理。
看看下面的例子:

#include <stdio.h>
//
//      ┏┛ ┻━━━━━┛ ┻┓
//      ┃       ┃
//      ┃   ━   ┃
//      ┃ ┳┛   ┗┳ ┃
//      ┃       ┃
//      ┃   ┻   ┃
//      ┃       ┃
//      ┗━┓   ┏━━━┛
//        ┃   ┃   神兽保佑
//        ┃   ┃   代码无BUG!
//        ┃   ┗━━━━━━━━━┓
//        ┃           ┣┓
//        ┃             ┏┛
//        ┗━┓ ┓ ┏━━━┳ ┓ ┏━┛
//          ┃ ┫ ┫   ┃ ┫ ┫
//          ┗━┻━┛   ┗━┻━┛

enum Year_State
{
	SPRING,
    SUMMER,
    AUTUMN,
    WINTER
};


void do_spring()
{
    printf("---------%s-------------\n",__FUNCTION__);
}

void do_summber()
{
    printf("---------%s-------------\n",__FUNCTION__);

}
void do_autumn()
{
    printf("---------%s-------------\n",__FUNCTION__);

}

void do_winter()
{
    printf("---------%s-------------\n",__FUNCTION__);

}


int main(int argc, const char *argv[])
{
    int state = SPRING;

    
    while (1)
    {
        if (state == SPRING)
        {
            do_spring();//相应的处理
            state = SUMMER;//状态改变
        }
        else if (state == SUMMER)
        {
            do_summber();
            state = AUTUMN;
        }
        else if (state == AUTUMN)
        {
            do_autumn();
            state = WINTER;
        }
        else if (state == WINTER)
        {
            do_winter();
            state = SPRING;
        }
        sleep(1);
    }
    
    
	return 0;
}

简单易懂,这里实现了四季的更替,因为只有四种状态,所以逻辑清楚,试想如果有个几十种状态,我们的if else将会变得十分之长,维护起来很麻烦,删减和添加状态变得不方便.但是通过这个例子我们认识到状态机的内涵.
如下图:
在这里插入图片描述
在状态1时,遇到一个事件,此刻发生状态转换,一般在状态转换前,先要进行事件的处理,然后改变状态位.然后进入状态2,以此类推.

使用switch case

这种做法和if else类似,结构上更清楚一些,代码如下:

int main(int argc, const char *argv[])
{
    int state = SPRING;

    
    while (1)
    {
        switch(state)
        {
            case SPRING:
                do_spring();
                state = SUMMER;//进入下一个状态
                break;
            case SUMMER:
                do_summber();
                state = AUTUMN;
                break;
            case AUTUMN:
                do_autumn();
                state = WINTER;
                break;
            case WINTER:
                do_winter();
                state = SPRING;
                break;
            default:
                break;
     
        }
          sleep(1);    
    }
	return 0;
}

函数指针实现FSM

使用函数指针实现FSM的思路:建立相应的状态表和动作查询表,根据状态表、事件、动作表定位相应的动作处理函数,执行完成后再进行状态的切换。

当然使用函数指针实现的FSM的过程还是比较费时费力,但是这一切都是值得的,因为当你的程序规模大时候,基于这种表结构的状态机,维护程序起来也是得心应手。

首先我们画出这个表
在这里插入图片描述

#include <stdio.h>
 //
//      ┏┛ ┻━━━━━┛ ┻┓
//      ┃       ┃
//      ┃   ━   ┃
//      ┃ ┳┛   ┗┳ ┃
//      ┃       ┃
//      ┃   ┻   ┃
//      ┃       ┃
//      ┗━┓   ┏━━━┛
//        ┃   ┃   神兽保佑
//        ┃   ┃   代码无BUG!
//        ┃   ┗━━━━━━━━━┓
//        ┃           ┣┓
//        ┃             ┏┛
//        ┗━┓ ┓ ┏━━━┳ ┓ ┏━┛
//          ┃ ┫ ┫   ┃ ┫ ┫
//          ┗━┻━┛   ┗━┻━┛

//定义状态数据的枚举类型
typedef enum Year_State
{
   SPRING = 1,
   SUMMER,
   AUTUMN,
   WINTER
}YEAR_START_E;

//定义事件的枚举类型
typedef enum Year_Event
{
    SPRING_EVENT = 1,
    SUMMER_EVENT,
    AUTUMN_EVENT,
    WINTER_EVENT,
}YEAR_EVENT_T;

//定义状态表的数据类型
typedef struct FsmTable_s
{
    int Event;               //事件
    int CurentState;           //当前状态
    void (*EventActFun)();  //函数指针
    int NextState;          //下一个状态
}FsmTable_T;



//定义处理函数及建立状态表
void do_spring()
{
    printf("---------%s-------------\n",__FUNCTION__);
}

void do_summber()
{
    printf("---------%s-------------\n",__FUNCTION__);

}
void do_autumn()
{
    printf("---------%s-------------\n",__FUNCTION__);

}

void do_winter()
{
    printf("---------%s-------------\n",__FUNCTION__);

}

FsmTable_T year_table[] = 
{
     //{到来的事件,当前的状态,将要要执行的函数,下一个状态}
    { SPRING_EVENT,  SPRING,    do_spring,  SUMMER },
    { SUMMER_EVENT,  SUMMER,    do_summber, AUTUMN },
    { AUTUMN_EVENT,  AUTUMN,    do_autumn,  WINTER },
    { WINTER_EVENT,  WINTER,    do_winter,  SPRING } 
    //add your codes here
};

typedef struct FSM_s{
    int CurState;//当前状态
    FsmTable_T * pFsmTable;//状态表
    int size;//表的项数
}FSM_T;

/*状态机注册,给它一个状态表*/
void FSM_Regist(FSM_T* pFsm, FsmTable_T* pTable)
{
    pFsm->pFsmTable = pTable;
}

/*状态迁移*/
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;  //函数指针初始化为空
    int NextState;
    int CurState = pFsm->CurState;
    int g_max_num = pFsm->size;
    int flag = 0; //标识是否满足条件
    int i;
 
    /*获取当前动作函数*/
    for (i = 0; i<g_max_num; i++)
    {
        //当且仅当当前状态下来个指定的事件,我才执行它
        if (event == pActTable[i].Event && CurState == pActTable[i].CurentState)
        {
            flag = 1;
            eventActFun = pActTable[i].EventActFun;
            NextState = pActTable[i].NextState;
            break;
        }
    }
 
 
    if (flag) //如果满足条件了
    {
        /*动作执行*/
        if (eventActFun)
        {
            eventActFun();
        }
 
        //跳转到下一个状态
        FSM_StateTransfer(pFsm, NextState);
    }
    else
    {
        printf("there is no match\n");
    }
}


int main(int argc, const char *argv[])
{
   
   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,SPRING_EVENT);
   printf("state:%d\n",year_fsm.CurState);

   printf("\n-------3--summer->autumn------\n");
   FSM_EventHandle(&year_fsm,SUMMER_EVENT);
   printf("state:%d\n",year_fsm.CurState);

   printf("\n-------4--autumn->winter------\n");
   FSM_EventHandle(&year_fsm,AUTUMN_EVENT);
   printf("state:%d\n",year_fsm.CurState);

   printf("\n-------5--winter->spring------\n");
   FSM_EventHandle(&year_fsm,WINTER_EVENT);
   printf("state:%d\n",year_fsm.CurState);


   printf("\n-------6--receive SUMMER_EVENT not SPRING_EVENT------\n");
   FSM_EventHandle(&year_fsm,SUMMER_EVENT);
   printf("state:%d\n",year_fsm.CurState);

   return 0;
}

测试结果:

-------1--init spring------
state:1

-------2--spring->summer------
---------do_spring-------------
state:2

-------3--summer->autumn------
---------do_summber-------------
state:3

-------4--autumn->winter------
---------do_autumn-------------
state:4

-------5--winter->spring------
---------do_winter-------------
state:1

-------6--receive SUMMER_EVENT not SPRING_EVENT------
there is no match
state:1

参考

https://www.jianshu.com/p/917c0fb8778b?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!