• QEP之init()和dispatch()流程图


    抽象状态机类QFsm或QHsm有一个函数指针,用于在继承的具体状态机类中指向具体的状态函数,其有两个对外的接口函数init()和dispatch(),其工作原理是理解状态机处理事件过程的关键。

    具体状态机类继承自QFsm或QHsm,同时继承了这个函数指针,用于动态指向具体状态机类中的私有状态函数。

    具体事件继承于根事件QEvent,并可以自己增加附加的属性。事件是外部与状态机唯一通信的实体,通过dispatch(),把事件送到状态机。状态机对外不可见,具体属性和具体状态函数都是私有的。

    QEP继承关系

         图1.QEP总体类结构
    

    1.预备知识

    (1)声明一个函数指针

    具体状态机类继承自QFsm或QHsm,则具体状态机具有了一个指针state,state可以指向任何状态函数,并调用状态函数执行。dispatch()函数可以用空事件探测状态机的结构、可以执行进入和退出动作、可以执行具体的事件处理动作,也可以进行状态转移。

    typedef uint8_t QState;                            
    typedef QState (*QStateHandler)(void *me, QEvent const *e);/*函数指针*/
    

    (2)声明一个状态机中的函数指针变量

    typedef struct QFsmTag {
        QStateHandler state; /*变量(函数指针),指向状态机当前状态(函数)*/
    } QFsm;
    
    typedef struct QFsmTag QHsm;
    

    (3)状态函数处理后的返回结果

    每个状态函数中,根据不同的事件处理,处理完后要返回上边的结果之一,供dispatch()了解状态函数对某事件是否忽略、是否处理完、是否转换、是否不能处理而要让父状态函数来处理。

    QSUPP(super)中的参数决定了层次状态机的层次结构。

    /* 忽略事件 */
    #define Q_IGNORED()         (Q_RET_IGNORED)
    
    /* 已处理事件 */
    #define Q_HANDLED()         (Q_RET_HANDLED)
    
    /* 状态转移 */
    #define Q_TRAN(target_)  
        (((QFsm *)me)->state = (QStateHandler)(target_), Q_RET_TRAN)
    
    /* 到超状态 */
    #define Q_SUPER(super_)  
        (((QHsm *)me)->state = (QStateHandler)(super_),  Q_RET_SUPER)
    

    (4)触发动作

    dispatch()用于主动去触发具体状态机,以探知状态机的结构、执行进入和退出动作。用QEPEMPTYSIG触发空动作,总是会执行到状态函数的最后一行QSUPPER(super_),通过触发后的返回结果,可以探知状态机的层次结构。

    /* 以sig_信号触发状态机 */
    #define QEP_TRIG_(state_, sig_) 
        ((*(state_))(me, &QEP_reservedEvt_[sig_]))
    
    /* 触发退出动作,在层次状态机HSM */
    #define QEP_EXIT_(state_) 
        if (QEP_TRIG_(state_, Q_EXIT_SIG) == Q_RET_HANDLED) { 
            ...QS 
        }
    
    /* 触发进入动作,在层次状态机HSM */
    #define QEP_ENTER_(state_) 
        if (QEP_TRIG_(state_, Q_ENTRY_SIG) == Q_RET_HANDLED) { 
            ...QS 
        }
    /* 触发空动作,在层次状态机HSM (自加)*/
    #define QEP_EMPTY_(state_) 
        QEP_TRIG_(state_, QEP_EMPTY_SIG_)  
    

    2.Fsm状态机init()和dispatch()流程

    (1)QFsm_init()流程
    QFsm_init流程

         图2.QFsm_init()流程
    

    (2)QFsm_dispatch()流程
    QFsm_dispatch流程

         图3.QFsm_dispatch()流程
    

    3.Hsm状态机init()和dispatch()流程

    从顶级状态的初始伪状态开始,到本初始伪状态转换的终状态(子状态),执行进入动作。在终状态(子状态)继续检查有没有子初始伪状态,如果有的话,继续进入,执行进入动作,直到最终状态。

    (1)QHsm_init()流程
    QHsm_init流程加状态机

         图4.QHsm_init()流程图与层次状态机
    

    (2)QHsm_dispatch()流程
    QHsm_dispatch--流程

         图5.QHsm_dispatch()流程图
    

    关键词:状态机;抽象状态机类;具体状态机类,状态函数;初始伪状态;父状态;超状态;源状态;终状态;最终状态。

    参考:
    【1】Miro Samek《UML状态图的实用C/C++设计---嵌入式系统的事件驱动型编程技术》第二版

  • 相关阅读:
    ubuntu进入可视化界面
    MYSQL(一)
    PHP(一)
    MAC下安装NLTK
    初次使用NLTK
    iPhone项目的BaseSDK和DeploymentTarget
    ratelimit+redis+lua对接口限流
    java操作RabbitMq
    二维码生成并在下方添加文字,打包下载
    Redis六大淘汰策略:新来的员工不小心把Redis服务器撑爆了!!!
  • 原文地址:https://www.cnblogs.com/hyper99/p/QEP-zhiinit--hedispatch--liu-cheng-tu.html
Copyright © 2020-2023  润新知