事件驱动型状态机EFSM介绍及C语言实现

一、什么是状态机?

有限状态机,(英语:Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。

有限状态机是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。在计算机科学中,有限状态机被广泛用于建模应用行为、硬件电路系统设计、软件工程,编译器、网络协议、和计算与语言的研究。
 

二、状态机的老的写法

按照状态机的理解,其写法一般有两种:竖着写和横着写。

2.1 竖着写(在状态中判断事件)

C代码片段:

cur_state = nxt_state;   
switch(cur_state) //在当前状态中判断事件
{            
    case s0: //在s0状态   
        if(e0_event) //如果发生e0事件,那么就执行a0动作,并保持状态不变;
        {   
        //执行a0动作;               
        //nxt_state = s0;  //因为状态号是自身,所以可以删除此句,以提高运行速度。
        } 
        else if(e1_event) //如果发生e1事件,那么就执行a1动作,并将状态转移到s1态;
        {   
            //执行a1动作;
            nxt_state = s1;
        }           
        else if(e2_event) //如果发生e2事件,那么就执行a2动作,并将状态转移到s2态;
        {  
            //执行a2动作;
            nxt_state = s2;
        }
        else
        {
            break;    
        }   

    case s1: //在s1状态
        if(e2_event) //如果发生e2事件,那么就执行a2动作,并将状态转移到s2态; 
        {                
            //执行a2动作;
         nxt_state = s2;
        }           
        else
        {
      break;
        }

    case s2: //在s2状态
        if(e0_event)  //如果发生e0事件,那么就执行a0动作,并将状态转移到s0态;
        {
            //执行a0动作;               
            nxt_state = s0;
        }
}

2.2 横着写(在事件中判断状态)

C代码片段:

//e0事件发生时,执行的函数
void e0_event_function(int * nxt_state)
{   
    int cur_state;   
    cur_state = *nxt_state;   
    switch(cur_state)
    {       
        case s0: //观察表1,在e0事件发生时,s1处为空   
        case s2: //执行a0动作;           
        *nxt_state = s0;
    }
}

//e1事件发生时,执行的函数
void e1_event_function(int * nxt_state)
{   
    int cur_state;   
    cur_state = *nxt_state;   
    switch(cur_state)
    {       
        case s0: //观察表1,在e1事件发生时,s1和s2处为空           
            //执行a1动作;           
            *nxt_state = s1;
    }
}

//e2事件发生时,执行的函数
void e2_event_function(int * nxt_state)
{   
    int cur_state;   
    cur_state = *nxt_state;   
    switch(cur_state)
    {       
        case s0: //观察表1,在e2事件发生时,s2处为空       
        case s1:           
            //执行a2动作;           
            *nxt_state = s2; 
    }
}

上面横竖两种写法的代码片段,实现的功能完全相同,但是,横着写的效果明显好于竖着写的效果。具体原因相信大家都能明白。

三、新型事件驱动型有限状态机实现

一般情况下,大家一想到状态机,核心考虑的都是软件代码的逻辑层面,使用状态机能够将代码的逻辑层次和状态清晰的表现出来,以便于代码的实现。

但实际情况是:状态机不仅仅可以表示代码的逻辑层次和逻辑关系,还能很好的将源代码做到分离和区分,从而实现代码框架的时间与空间的隔离(逻辑与存储的分离),这才是状态机存在的真正价值和实际意义

比如前面两种老的状态机写法,除了switch()的代码可以放在顶层目录下的源码外,各个状态/事件下的代码可以根据状态/事件进行子文件夹命名,然后把相关的代码放在对应的文件夹中。这样就可以很好的根据不同状态进行人员分工,还可以实现并行开发了

但这样,问题又来了:这样虽然把物理代码分离了,但是各个状态/事件下的代码是需要交互的,是有逻辑沟通的

要解决这个问题,就要站在面向对象的角度来思考了:我们把每一个状态看成一个实际的对象,每个对象都会处理一组相同的事件,对于某个状态对象不关心的事件,只需要将对应的处理置位NULL即可

基于这个思想,我实现了一套EFSM(Event Finite State Machine),目前已经基于MIT协议完全开源了。下面是代码地址:

  • 码云(Gitee):https://gitee.com/simpost/EFSM
  • GitHub:https://github.com/AaronKonishi/EFSM

具体实现理论方法是:内部每个状态已事件-处理的key-value对的形式保存为一个hash表,不同的状态对应一个hash表;我们的状态机就是一个指向这个hash表的指针而已,整个状态机机制实现全部由efsm_event.h和efsm.h两个头文件实现!同时,为了简化应用,我还定义了一个运转状态机的线程(efsmt.c/efsmt.h),并且采用面向对象的方法,实现了命名空间的独立!

换句话说,只要你合理安排不同的模块,你可以在一个进程中创建多个状态机,你甚至可以通过EFSM实现层次状态机。

那么,基于EFSM开发模块/项目,我们核心要做的就是定义清楚各个事件,以及真正的状态对象即可

接下来一篇,将详细介绍EFSM的接口和使用方法,详见:

https://blog.csdn.net/a123441/article/details/89841160

有关技术的更多干货和分享,可关注我的个人公众号,内容涵盖单片机、FreeRTOS、Linux驱动、Linux驱动、Linux中间件、产品原型设计、设计模式、软件框架、软件重构、网络设计、数据库、人工智能、深度学习等多方面内容,内容将持续不断更新。

事件驱动型状态机EFSM介绍及C语言实现_第1张图片

 

你可能感兴趣的:(软件架构与常用模块)