zoukankan      html  css  js  c++  java
  • c状态机

    https://www.jianshu.com/p/917c0fb8778b?utm_campaign=maleskine&utm_content=note&utm_medium=reader_share&utm_source=weixin&from=timeline

    有限状态机(finite state machine)简称FSM,表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用。FSM是一种逻辑单元内部的一种高效编程方法,在服务器编程中,服务器可以根据不同状态或者消息类型进行相应的处理逻辑,使得程序逻辑清晰易懂。
    状态机实现的方式有多种,下面讲述三种.
    1.使用if/else if语句实现的FSM
    使用if/else if语句是实现的FSM最简单最易懂的方法,我们只需要通过大量的if /else if语句来判断状态值来执行相应的逻辑处理。
    看看下面的例子:

    include <stdio.h>

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

    void spring_thing()
    {
    printf("hello spring ");
    }
    void summer_thing()
    {
    printf("hello summer ");
    }
    void autumn_thing()
    {
    printf("hello autumn ");
    }
    void winter_thing()
    {
    printf("hello winter ");
    }

    int main()
    {
    int state = SPRING;
    while (1)
    {
    if (state == SPRING)
    {
    spring_thing();//相应的处理
    state = SUMMER;//状态改变
    }
    else if (state == SUMMER)
    {
    summer_thing();
    state = AUTUMN;
    }
    else if (state == AUTUMN)
    {
    autumn_thing();
    state = WINTER;
    }
    else if (state == WINTER)
    {
    winter_thing();
    state = SPRING;
    }
    sleep(1);
    }

    return 0;
    

    }

    简单易懂,这里实现了四季的更替,因为只有四种状态,所以逻辑清楚,试想如果有个几十种状态,我们的if else将会变得十分之长,维护起来很麻烦,删减和添加状态变得不方便.但是通过这个例子我们认识到状态机的内涵.
    如下图:

    在状态1时,遇到一个事件,此刻发生状态转换,一般在状态转换前,先要进行事件的处理,然后改变状态位.然后进入状态2,以此类推.
    2.使用switch case
    这种做法和if else类似,结构上更清楚一些,代码如下:

    int main()
    {
    int state = SPRING;
    while (1)
    {
    switch(state){
    case SPRING:
    spring_thing();
    state = SUMMER;
    break;
    case SUMMER:
    summer_thing();
    state = AUTUMN;
    break;
    case AUTUMN:
    autumn_thing();
    state = WINTER;
    break;
    case WINTER:
    winter_thing();
    state = SPRING;
    break;
    default:
    break;

        }
        sleep(1);
    }
    
    return 0;
    

    }

    3.函数指针实现FSM
    使用函数指针实现FSM的思路:建立相应的状态表和动作查询表,根据状态表、事件、动作表定位相应的动作处理函数,执行完成后再进行状态的切换。
    当然使用函数指针实现的FSM的过程还是比较费时费力,但是这一切都是值得的,因为当你的程序规模大时候,基于这种表结构的状态机,维护程序起来也是得心应手。
    首先我们画出这个表

    代码关键部分:

    1.定义状态数据的枚举类型
    enum year_state
    {
    SPRING = 1,
    SUMMER,
    AUTUMN,
    WINTER
    };

    2.定义事件的枚举类型
    enum year_event
    {
    EVENT1 = 1,
    EVENT2,
    EVENT3,
    EVENT4,
    };

    3.定义状态表的数据类型
    typedef struct FsmTable_s
    {
    int event; //事件
    int CurState; //当前状态
    void (*eventActFun)(); //函数指针
    int NextState; //下一个状态
    }FsmTable_t;

    4.定义处理函数及建立状态表
    void spring_thing()
    {
    printf("this is spring ");
    }
    void summer_thing()
    {
    printf("this is summer ");
    }
    void autumn_thing()
    {
    printf("this is autumn ");
    }
    void winter_thing()
    {
    printf("this is winter ");
    }

    FsmTable_t year_table[] =
    {
    //{到来的事件,当前的状态,将要要执行的函数,下一个状态}
    { EVENT1, SPRING, summer_thing, SUMMER },
    { EVENT2, SUMMER, autumn_thing, AUTUMN },
    { EVENT3, AUTUMN, winter_thing, WINTER },
    { EVENT4, WINTER, spring_thing, SPRING },
    //add your codes here
    };

    5.状态机类型,及状态机接口函数
    /状态机类型/
    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].CurState)
        {
            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
    ");
    }
    

    }

    测试程序代码为:
    /state.c/

    include <stdio.h>

    enum year_state{
    SPRING = 1,
    SUMMER,
    AUTUMN,
    WINTER
    };

    enum year_event{
    EVENT1 = 1,
    EVENT2,
    EVENT3,
    EVENT4,
    };

    typedef struct FsmTable_s{
    int event; //事件
    int CurState; //当前状态
    void (*eventActFun)(); //函数指针
    int NextState; //下一个状态
    }FsmTable_t;

    void spring_thing()
    {
    printf("this is spring ");
    }
    void summer_thing()
    {
    printf("this is summer ");
    }
    void autumn_thing()
    {
    printf("this is autumn ");
    }
    void winter_thing()
    {
    printf("this is winter ");
    }

    FsmTable_t year_table[] =
    {
    //{到来的事件,当前的状态,将要要执行的函数,下一个状态}
    { EVENT1, SPRING, summer_thing, SUMMER },
    { EVENT2, SUMMER, autumn_thing, AUTUMN },
    { EVENT3, AUTUMN, winter_thing, WINTER },
    { EVENT4, WINTER, spring_thing, 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].CurState)
        {
            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
    ");
    }
    

    }

    int main()
    {
    FSM_t year_fsm;
    FSM_Regist(&year_fsm,year_table);
    year_fsm.curState = SPRING;
    year_fsm.size = sizeof(year_table)/sizeof(FsmTable_t);

    printf("
    -------1--init spring------
    ");
    printf("state:%d
    ",year_fsm.curState);
    
    printf("
    -------2--spring->summer------
    ");
    FSM_EventHandle(&year_fsm,EVENT1);
    printf("state:%d
    ",year_fsm.curState);
    
    printf("
    -------3--summer->autumn------
    ");
    FSM_EventHandle(&year_fsm,EVENT2);
    printf("state:%d
    ",year_fsm.curState);
    
    printf("
    -------4--autumn->winter------
    ");
    FSM_EventHandle(&year_fsm,EVENT3);
    printf("state:%d
    ",year_fsm.curState);
    
    printf("
    -------5--winter->spring------
    ");
    FSM_EventHandle(&year_fsm,EVENT4);
    printf("state:%d
    ",year_fsm.curState);
    
    printf("
    -------6--receive EVENT2 not EVENT1------
    ");
    FSM_EventHandle(&year_fsm,EVENT2);
    printf("state:%d
    ",year_fsm.curState);
    
    return 0;
    

    }

    结果为:
    -------1--init spring------
    state:1

    -------2--spring->summer------
    this is summer
    state:2

    -------3--summer->autumn------
    this is autumn
    state:3

    -------4--autumn->winter------
    this is winter
    state:4

    -------5--winter->spring------
    this is spring
    state:1

    -------6--receive EVENT2 not EVENT1------
    there is no match
    state:1

  • 相关阅读:
    【转】C++ 实现线程池
    【转】C++ 实现reactor 模式
    【转】C++ 单例模式
    高并发的内存池——TLS MEMMORY POOL
    爬取某东商品数据
    查看解放号的一些Python岗
    查看前程无忧Python岗及一些可视化
    爬某牙小姐姐视频
    爬取某云音乐热歌榜
    键盘及鼠标记录程序
  • 原文地址:https://www.cnblogs.com/retry/p/11607776.html
Copyright © 2011-2022 走看看