事件驱动框架(二)——状态机

模板方法+事件驱动设计任务状态机 任务包含状态和事件,状态即用户任务当前所处的阶段,比如未绑定、待开启、进行中、待领奖和已完成这些阶段。或许一开始简单的任务模块就能支撑,但是随着越来越多的运营活动出现的时候,代码就会开始不断堆积变得难以维护,任务状态的流转甚至变得不可控,开发成本直线上升,因此需要一个易于扩展可读性高的任务状态机。模板定义了任务的基本属性,包括任务名称、行为到事件的映射、完成任务的通知和完成任务的奖励等等。用户一个行为可能触发多个任务状态的流转,当上报用户行为时,通过模板配置的行为和事件的映射关系触发对应的事件发布。 阅读详情
AI摘要

本文介绍了事件驱动框架中的状态机实现原理,包括有限状态机(FSM)与层次状态机(HSM)的区别,以及如何在嵌入式编程中应用状态机进行事件处理。探讨了不同状态机处理方式的特点,并详细解析了状态表实现方法。

事件驱动框架(二)

说明

本篇接上一篇事件驱动框架之后,介绍状态机的原理相关的,以及事件驱动框架下事件处理状态机的实现。因为代码大多还是参照QP源码,所以仅供学习使用。


有限状态机介绍

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

引用百度百科:http://baike.baidu.com/link?url=H4dYy2lfIm5yiGVQ0ExlYjEKCHFwByR1iBaySgXcQke9K7C4xPF05Ji8mYyvTzrTlzKBg9UJDXLhtbe_DGdtbWlcMUK-u3XdTpzlNODiLkR8vfU2YfqJxBy1L0YnurXcjBzG2HXC0R1Dkks3wkQz2a

状态机的概念在很多地方都有用到。我在学数字电路的时候和编程的时候都有接触过这种数学模型:其实说白了就是一种数学模型,它的原理都是相似的。这里主要在嵌入式编程中的引用。
网上应该有状态机最简单的点小灯的例子来借助理解状态机怎么编程,这里就直接放传送门了。

传送门空缺中。。。。

当然还有种层次状态机(HSM),这种直接把有限状态机(FSM)给包括进去了。结构上具有层次性,而且设计和实现都比较复杂。可以记住UML图来进行设计。


事件处理状态机的实现

该部分参考了一部分的QP框架。QP的设计主要实现层次为实现层次状态机(HSM)的方式:规定每次事件处理完后的状态返回值(这个主要是根据UML图的模型,也就是必须开发者之前设计过的来实现的),状态转换过程中会自动根据返回值,判断实现是否需要调用进入和退出的状态回调。但是该种方式有一个缺点:它需要开发者对QP非常了解这个框架,函数回调是采用列举事件(switch)的方式,并且需要自己逻辑上使用状态机的编程思想,并且需要严格对照着UML图的状态转换方式进行编程。

一.状态机的常见处理方式:

下再介绍几种常用的状态机处理方式:但这些都不外乎提供2个接口:dispatch和initial。initial为初始化函数,即负责这个状态机控制的对象的初始化,及其设置状态机的初始状态。dispatch接口用来给状态机派发一个事件。

1>.在dispatch中列出所有的状态及对应的事件。

其实QP在这个功能上有点隐藏状态的意思。缺点就是需要把所有状态和时间都罗列,代码的重用性较低,内容容易膨胀。

2>.状态表(State Table)

该种方式是将事件和状态绑定到一张二维表上,然后根据不同的状态和时间进行规律的映射到这张表上,进行事件处理的回调。
缺点:这是一张静态的状态表,需要列举出所有的事件和状态,但状态和事件的类型增多时,维护就变得比较困难。

3>.面向对象的设计模式

这种方式是把状态机作为一个对象,将状态的原型作为一个抽象类,然后子状态(具体状态)继承于抽象类,完成它的具体实现。个人感觉这种方式和上一种差不多,不过上一种相对来说多出了一张状态表。
缺点:多态的实现用C语言比较麻烦。如果继承每个状态还是需要列举出所有状态的实现的,如果对应的状态的事件为空,还是需要建立某个响应,比较浪费内存。如果是继承dispatch,则也需要在单个函数体内列举出事件响应。

4>.pt协程

PT协程会在后面专门章中介绍。

二.FSM的策略

由于这个框架主要还是为了来做GUI的。整个框架采用事件驱动的结构来实现,主要形式采用状态表的形式。
这里讨论一点:就是HSM和FSM的关系。HSM是一种覆盖面很广的模型,包括了各种状态机的模型。但他的层次特征主要体现在对相同的状态类进行抽象,把同样的动作进行归并,比如说一个层次包含了它内包含多个具体状态的进入和退出的相同的操作。这样就减少了代码量和逻辑上的重复性。但如果不用抽象的概念,HSM依然是可以展开成拓展型FSM的(对于这种状态机有个专业的名字,忘了)。而QP的主要的状态机还是针对于HSM模型的,但HSM不容易理解,这也可能是限制了QP推广的原因。
因此在形式上,之前使用过的MATLAB的GUIDE和VB甚至是C#的界面设计时,他的动作响应callback回调函数令我印象深刻。比如:我希望鼠标按下图形化按钮后进行一个动作。这里我只需要在那个动作响应的函数里编程就可以了,剩下的事整个框架则会帮我自动完成,我无需关心它是如何被调用的。利用这个想法,因此我更偏向于使用状态表的方式。但是为了兼容一些类型的状态机,我仿照了QP的一些做法,并可选择性的保留了entry和exit的回调。当然,如果当前对象如果对此并没有要求,则可以省去。
除了SGUI以外,对于其他的对象来说,也可以采取这种策略或者其他几种常见的处理方式。

三.具体实现

1.事件的实现

事件作为驱动整个框架的关键,对象之间通过接受事件,进行响应处理,状态的转化。事件驱动的结构如下:

typedef  struct  AEvtTag  AEvt;
struct AEvtTag
{
        ASignal sig;         /* 事件信号量 */
        uint16_t poolID;      /* 内存池编号,对应的是事件块编号 */
};

ASignal 为型号量的类型,信号的多少可以在头文件中定义,选择不超出范围的大小。poolID是对应的事件编号。动态事件是从内存池中分配出来的,可以动态生成和释放,而静态事件则不能。

2.状态机的实现(SGUI的状态机)

状态机的机构如下:

struct AFsmTag
{
        const AStateHandler * state_table;  /* 指向状态表 */
        ASignal  n_signals;                 /* 信号量总数 */
        uint8_t  n_states;                  /* 状态总数 */
        uint8_t  state;                     /* 当前状态编号 */
        uint8_t  method ;                   /* 方式: 提供2种:是否省略进入退出动作,默认忽略。
                                             这里设置这个主要是为了省内存,如果找到更好的映射方式时改进*/
        AStateHandler initial;              /* 初始化 转换 */

};

其中大部分都是状态表设计的原型,用来辅助查表的实现的。这里我增加了一个method的变量,用来标志着个是否是基础的FSM带进入entry和exit的事件的。如果对于状态较多的对象,如果不需要用到进入和退出的动作不必要,则可以省去一大笔空间。
dipatch函数主要是实现事件的派送交给响应函数处理,另外如果有entry和exit,则会自动调用。不过这里有个比较麻烦的问题:用户在每次处理函数过后还是需要返回一个状态值(改变状态或者不改变)。

3.初始化

状态机初始化代码如下:显示调用初始化接口

/*!     预留信号状态     */
enum 
{
    A_ENTRY_SIG = 0,                     /* 进入状态动作 */
    A_EXIT_SIG,                          /*退出状态动作 */
    A_DEFAULT_SIG                        /*用户预留信号 */
};

void AFsm_init(AFsm *me)
{
        AStateHandler t;
        (me->initial)(me, (AEvt *)0);  //调用对象初始化函数
        assert((me->state) < (me->n_state));
        if ((me->method == FSM_DEFAULT_METHOD))       
        {
            t = *(me->state_table + me->state * me->n_signals + A_ENTRY_SIG);  //默认进入预留 
            (*t)(me, (void *)0);
        }
        else
        {
            t = *(me->state_table + me->state * me->n_signals);          //默认进入第一个状态
            (*t)(me, (void *)0);
        }
}

前面的枚举量为预留进入退出的信号标识。如果设置为FSM_DEFAULT_METHOD模式,则需要在该对象的第一个信号枚举=A_DEFAULT_SIG。那SGUI的自定义的一个响应举例:

/*! 自定义按键 */
enum KeyCode
{
        TICK_SIG = A_DEFAULT_SIG,           
        UP_KEY_SIG,
        DOWN_KEY_SIG,
        LEFT_KEY_SIG,
        RIGHT_KEY_SIG,
        CONFIRM_KEY_SIG,
        GUI_MAX_SIG
};

这样就默认将进入和退出的信号无形中加入到自定义的信号钱

初始化接口会自动调用对象的初始化函数,再将状态转换到默认状态:如果有设置状态的退出进入则会默认进入entry状态进行执行,否则进入第一个状态的第一个响应进行执行。(这里想着是否能改进一下,制定一下第一次进入的状态和时间)。

4.调度

状态机调度代码如下:

void AFsm_dispatch(AFsm * me, AEvt const * e)
{
    AStateHandler t;
    uint8_t sta;
    assert(e);//事件合法性
    assert(state);//状态合法性
    sta = me->state;
    t = *(me->state_table + me->state * me->n_signals + e->sig);  //获取状态表中的函数指针

    if ((*t)(me, e) == A_RET_TRANS && (me->method == FSM_DEFAULT_METHOD))  //得到执行结果
    {
        /* 调用退出 */
        t = *(me->state_table + sta * me->n_signals + A_EXIT_SIG);
        (*t)(me, (void *)0);

        /* 调用进入 */
        t = *(me->state_table + me->state * me->n_signals + A_ENTRY_SIG);       
        (*t)(me, (void *)0);
    }
}

如果该对象没有设置进入或者退出状态,则不执行进入退出段响应的代码。如果有设置FSM_DEFAULT_METHOD模式则在状态发生改变时自动调用进出状态的函数。

4.状态空响应

状态空响应的代码用来填充到状态表中对应状态和事件什么都不做的位置。这部分代码如下:

void AFsm_empty(AFsm * me, AEvt const * const e)
{
        (void)me;
        (void)e;
}

四.小结

事件处理的状态机大概就这样了,原型还是用了状态表的原理。后来有听别人说过PT协程的方法来封装状态机,大概记得的印象中主要就是把while-case的结构隐藏到范式中,但实际上还是状态机的结构,但整体上看起来就和顺序编程没什么差别。因为看过很久了,而且正好要思考怎么拓展框架的灵活性,所以会单独拉一张来介绍下PT协程。

[RDMA]QP相关介绍(二)——QP State Machine Modify QPModify QPModify QPModify QP—RQ WR发布,但不处理RQ WR。如果QP接收任何入站请求包,应将其丢弃。—禁止SQ WR发布与处理。—RQ 发布与处理。RQ Logic可以处理入站message。如果是RC或RD QP,将生成远端QP的SQ Logic将接收的请求包的响应。—禁止SQ WR发布与处理。—WR可同时发布到SQ与RQ。—两个队列上的WR都会被处理。SQ Logic可以处理SQ WQE,并生成向远端QP的RQ Logic发送的出站请求包。 阅读详情

相关推荐

层次状态机-HSM代码解析

有限状态机在学习和工作中经常能够遇到,前面的文章也有使用到。但是对于层次状态机网上的学习资源却很少,导致一直不理解这个工作机制,后面偶然在GitHub看到一篇文章,深入学习后发现层次状态机太实用了,如果将其在项目上结合,肯定能够创造出一个比较好的代码框架。

frank 3400

嵌入式开发绝招:状态机+事件驱动框架

生活中有很多事件驱动的例子,上自习瞒着老师偷睡觉就是很生动的一个。我们都是从高中时代走过来的,高中的学生苦啊,觉得睡觉是世界上最奢侈的东西, 有时候站着都能睡着啊!老师看的严,上课睡觉不允许 啊,要挨批啊!有木有!相比而言,晚自习是比较宽松的,老师只是不定时来巡视,还是有机会偷偷睡一会儿的。现在的问题是,怎么睡才能既睡得好又不会让老师发现呢?晚自习是比较宽松的,老师只是不定时来巡视,还是有机会偷偷睡一会儿的。现在的问题是,怎么睡才能既睡得好又不会让老师发现呢?

FMgxth的博客 3841

嵌入式状态机编程-QP状态机框架与常见状态机方法

状态机基本术语 现态:是指当前所处的状态。 条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。 动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。 次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。 传统有限状态机Fsm实现方法 如图,是一个定时计数器,计数器存在两种状态,一种为设置状态,一种为计时状态 设

qq_36969440的博客 9665

QP 状态机:嵌入式实时框架

**QP™/C Real-Time Embedded Framework (RTEF)** 是专门为 real-time embedded (RTE) 系统量身定制的 Active Object model of computation 的轻量级实现。QP 既是用于构建由 active objects(actors) 组成的应用程序的软件基础设施,也是用以确定方式执行 active objects 的运行时环境。另外,QP 支持 Hierarchical State Machines(分层状态机)用它来指定

weixin_45787009的博客 4468

嵌入式开发:状态机+事件驱动框架

搬运+9 抄过来的,绝对是干货呀,虽然现阶段还用不了,以后一定会用到的

1+1>2 1859

QT—状态机框架

QT-状态机框架 概念 创建状态机 在状态机中使用动画 1默认动画 2.检测状态中的所有属性都已经被设置 3动画结束前退出状态会发生什么 状态机的其他特性 1.为状态分组来共享切换 2.使用历史状态来保存或者恢复当前状态 3.使用并行状态来避免组合爆炸 4.检测复合状态的结束信号 5.无目标切换 6.事件、切换和守护 7.使用恢复策略自动恢复属性...

Half-up的博客 3456

事件驱动框架(二)——状态机【转】

转自:https://blog.youkuaiyun.com/dfsae/article/details/52995034 事件驱动框架(二) 说明 本篇接上一篇事件驱动框架之后,介绍状态机的原理相关的,以及事件驱动框架下事件处理状态机的实现。因为代码大多还是参照QP源码,所以仅供学习使用。 有限状态机介绍 有限状态机,(英语:Finite-state machine, FSM),又称有限状态自...

weixin_34072458的博客 712

QP(状态机事件驱动型框架)

QP框架是量子计算平台(Quantum Platform)的简称,其核心采用层次式状态机(HFSM)解决复杂状态管理问题。HFSM通过状态嵌套机制,支持子状态机分层管理,既能处理互斥状态(如移动/闲置),又能管理包含关系状态(如移动下的行走/奔跑)。相比传统状态机,HFSM使复杂逻辑更清晰,代码结构更合理,特别适合处理行为复杂度持续增长的系统开发需求。该框架借鉴量子跃迁理念,为事件驱动型应用提供完整开发平台。

weixin_55255438的博客 720

QP状态机框架与常见状态机方法

原文链接:嵌入式状态机编程-QP状态机框架与常见状态机方法 状态机基本术语 现态:是指当前所处的状态。条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。 传统有限状态机Fsm实现方法 如图,是一个定时

jin787730090的博客 2412

事件驱动和状态机模式在YARN中的使用

阅读了下YARN的源码,架构中设计模式除了服务生命周期管理模式外,还包括事件驱动和状态机模式。生命周期管理模式在容器设计时候比较常见,包括资源模型的加载,卸载等等,比如tomcat、jboss等开源产品。 这里重点讲一下事件驱动和状态机模式的使用。 从提交任务到任务处理完成,YARN架构中整个任务的处理过程的设计都是事件驱动和状态机器的模式。 对于事件驱动模式,对象包括事件类型EventTy

云计算、分布式架构、K8S、大数据、机器学习、搜索、推荐、广告 6800

嵌入式开发中的状态机与事件驱动框架实践

状态机与事件驱动是嵌入式系统开发中的核心设计模式。状态机通过有限状态和转换规则描述系统行为,特别适合处理具有明确状态划分的业务逻辑;事件驱动则通过异步响应机制提升系统效率,相比轮询方式能显著降低CPU占用。这两种模式在嵌入式领域具有重要技术价值,广泛应用于智能家居控制、工业自动化等场景。本文以按键检测和门禁系统为例,详细解析了状态表驱动法和消息队列等实现方式,并提供了中断优化、状态机调试等工程实践技巧。通过结合DMA传输和优先级队列等优化手段,可使系统响应速度提升30%以上。

weixin_30336531的博客 582

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

一、什么是状态机? 有限状态机,(英语:Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。 有限状态机是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。在计算机科学中,有限状态机被广泛用于建模应用行为、硬件电路系统设计、软件工...

小银子 7183

状态机框架设计——分层状态机与事件驱动架构(HSM、QP框架)

摘要:在嵌入式系统复杂度日益增长的今天,传统的"大循环+标志位"架构已难以应对多源异步事件、复杂状态流转及严格时序要求。本文深入探讨分层状态机(HSM)与事件驱动架构的融合设计,从UML状态图理论到QP框架的工程实践,提供一套可直接落地的轻量级状态机框架实现,涵盖状态树管理、事件冒泡分发、Active Object并发模型、内存池管理及完整测试调试方案。/* smart_lock_hsm.c - 智能门锁状态机实现 *//* ========== 状态前向声明 ========== */

从事移动开发八年,csdn博客专家,阿里云特邀专家,华为云云享专家,高级网络信息安全工程师,大数据工程师(高级),python技术开发(高级),HarmonyOS 应用开发者高级认证,现在某学校任教。 1万+

事件驱动框架(一)

事件驱动框架中的状态机

忧愁的awe的博客 6808

【win11】主板更新之后pin不可用,恢复方法

台式机的主板更新了BIOS,再开机竟然登录不进去系统了。 登录界面上显示:【由于此设备上的安全设置已更改,你的pin码不再可用。单击以重新设置pin】 点击【单击以重新设置pin】没有任何反应。 也没有密码登录选项。 在网上找到解决方法,不用PE,只需要按步骤操作即可。通过实际验证可行,现记录如下。

1万+

STM32中断实战:用ITR9606红外传感器DIY转速计数器(附完整代码)

本文详细介绍了如何使用STM32中断机制和ITR9606红外传感器DIY高精度转速计数器。从传感器选型、中断配置到抗干扰设计,提供完整的实战指南和优化代码,特别适合嵌入式开发者和硬件工程师快速实现工业级转速检测系统。

weixin_29159613的博客 289

状态机+事件驱动框架

最近看到一篇关于状态机相关分享。

FREEDOM_X的专栏 266

永磁同步电机矢量控制(十一)——基于损耗模型的PMSM效率优化策略

本文深入探讨了永磁同步电机(PMSM)基于损耗模型的效率优化策略,详细分析了铜损和铁损的构成与建模方法,并提出了最小损耗控制策略的实现方案。通过与传统MTPA控制的对比,展示了在不同工况下的效率提升效果,同时讨论了工程实现中的关键问题与解决方案,为PMSM的高效运行提供了理论支持和实践指导。

7z8x2c4v6b9的博客 231

嵌入式开发绝招:状态机+事件驱动框架~

关注、星标公众号,直达精彩内容 作者|Alicedodo状态机是一种思想,事件驱动也是一种思想。事件驱动的概念生活中有很多事件驱动的例子,上自习瞒着老师偷睡觉就是很生动的一个。我们都是从高中时代走过来的,高中的学生苦啊,觉得睡觉是世界上最奢侈的东西, 有时候站着都能睡着啊!老师看的严,上课睡觉不允许 啊,要挨批啊!有木有!相比而言,晚自习是比较宽松的,老师只是不定时来巡视,还是有机会偷偷睡一...

李肖遥的专栏 1596

第 13 章:Spring AI Alibaba MCP 与 Nacos3 — 企业级MCP服务

理解Spring AI Alibaba 框架下的MCP服务与Nacos注册中心整合的必要性,学会Spring AI Alibaba-基于Nacos的MCP实现方法

paopao_wu的专栏 788

本地玩转AI还得靠这个,SillyTavern(酒馆)到底有多强?

SillyTavern是一款本地运行的LLM交互前端,支持文本生成、图像生成、语音合成等功能。它最初是TavernAI的分支,现已独立开发,社区活跃,功能更新频繁。SillyTavern通过前端UI和插件系统连接各种大模型后端,如OpenAI、KoboldAI等,用户可以在本地创建“虚拟酒馆”与各种角色对话。其功能亮点包括角色卡、角色记忆、世界设定、多人聊天室、自定义UI和行为脚本、插件扩展支持等。SillyTavern适合AI创作用户、AI工程师、LLM爱好者和AIGC创作者。它有两个维护分支:relea

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 8037

Qt状态机框架

状态机框架提供了用于创建和执行状态图的类。这些概念和符号基于Harel的Statecharts:复杂系统的可视化形式(),也是UML状态图的基础。状态机执行的语义基于状态图XML (SCXML)(状态图提供了一种图形化的方式来模拟系统对刺激的反应。这是通过定义系统可能处于的状态,以及系统如何从一个状态移动到另一个状态(状态之间的转换)来完成的。事件驱动系统(如Qt应用程序)的一个关键特征是,行为通常不仅取决于最近的或当前的事件,还取决于在它之前的事件。使用状态图,这些信息很容易表达。

qq_32640443的博客 1274

Silly Tavern酒馆ai角色卡与世界书导入超详细教程!

前几天,我在设置 Silly Tavern 的时候,想导入一个喜欢的角色卡,结果发现不少朋友其实已经下载好了角色资源,但却不知道怎么正确导入使用。这篇文章就作为一份完整的新手向教程,一步步教你如何在 Silly Tavern 中导入角色卡、世界书,并实现与 AI 角色的真实互动。如果你是第一次接触这个功能,建议先收藏慢慢看~点击菜单栏上的 图标,打开角色界面。初始状态下,你应该只看到默认角色 Seraphina。你可以先点击她的头像尝试聊天,也可以导入自己喜欢的角色。点击导入按钮,选择你下载好的角色卡(通

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 2万+
上一篇: 事件驱动框架(一)
下一篇: 译:Finite State Machine Datapath Design, Optimization, and Implementation(一)
忧愁的awe
博客等级 码龄14年 274粉丝 46原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值