SMC状态机 讲解2 从模型到SMC
SMC状态机 讲解2 从模型到SMC
- 1、实例化有限状态机(FSM)
- 2、简单转换 Simple Transition
- 3、外部环回转换 External Loopback Transition
- 4、内部环回转换 Internal Loopback Transition
- 5、转换动作
- 6、转换Guard
- 7、转换参数
- 8、Entry 和 Exit动作
- 9、Push 转换
- 10、Pop转换
- 11、默认转换
1、实例化有限状态机(FSM)
private final AppClassContext _fsm;public AppClass()
{// 初始化应用程序类// 实例化有限状态机// 注意:传递给FSM是安全的// 构造函数,因为只有FSM的构造函数// 将其存储在数据成员中_fsm = new AppClassContext(this);
}// 实例化后输入FSM启动状态
// 应用对象
public void startWorking()
{_fsm.enterStartState();return;
}
2、简单转换 Simple Transition
// State
Idle
{// 转换到下一个状态的动作Run Running {}
}
状态和转换名称的命名规则必须为“[A- za -z_][A- za -z0-9_]*”形式。
3、外部环回转换 External Loopback Transition
// State
Idle
{// 转换到下一个状态的动作Timeout Idle {}
}
外部环回确实离开当前状态并返回到当前状态。这意味着执行状态的exit和entry操作。这与内部环回转换相反。
4、内部环回转换 Internal Loopback Transition
// 状态
Idle
{// 转换到下一个状态的动作Timeout nil {}
}
使用“nil”作为下一个状态将导致转换保持在当前状态,而不是离开它。这意味着状态的退出和进入操作不会被执行。这与外部环回转换相反。
5、转换动作
// 状态
Idle
{//转换Run// 下一个状态Running// 动作{StopTimer("Idle");DoWork();}
}
- 转换的动作必须包含在“{}”中。
- 动作的形式为“[A-Za-z] [A-Za-z0-9_ -] *()”。参数列表(argument list)必须为空或由逗号分隔的字面值组成。例如:整数(正数或负数、十进制、八进制或十六进制)、浮点数、双引号括起来的字符串、常量和转换参数。
- 操作必须是%class类中的成员函数,并且可以被状态机访问。通常这意味着c++中的公共成员函数或Java中的包。
动作参数包括:
4. 整数(例如1234)。
5. 浮点数(如12.34)。
6. 字符串(例如:“中的”)。
7. 一个转换参数。
8. 常量、#define或全局变量。
9. 独立的子程序或方法调用(例如event.getType())。
6、转换Guard
// State
Idle
{// TransRun// Guard condition[ctxt.isProcessorAvailable() == true &&ctxt.getConnection().isOpen() == true]// Next StateRunning// Actions{StopTimer("Idle");DoWork();}Run nil {RejectRequest();}
}
guard必须包含一个条件,该条件是有效的目标语言源代码——也就是说,它将是一个有效的“if”语句。定义的guard可能包含&&s、||s、比较运算符(==、<等)和嵌套表达式。SMC将您的保护条件逐字复制到生成的输出中。
如果guard条件的计算结果为true,则进行转换。如果gurad条件的计算结果为false,则发生以下情况之一(按优先级排序):
- 如果状态有另一个具有相同名称和参数的受保护转换,则检查该转换的保护。
- 否则,如果状态有另一个具有相同名称和参数列表的未保护转换,则进行该转换。
- 如果以上都不是,则遵循默认的转换逻辑。
一个状态可以有多个具有相同名称和参数列表的转换,只要它们都有唯一的gurad。当一个状态确实有多个具有相同名称的转换时,在排序它们时必须小心。状态机编译器将以与您使用的相同的从上到下的顺序检查转换,除了未保护的版本。只有当所有被保护的版本都失败时,才会采取这种做法。guard排序只有在guard不是互斥的情况下才重要,也就是说,对于同一个事件,多个gurad的值可能为true。
7、转换参数
// State
Idle
{// TransitionRun(msg: const Message&)// Guard condition[ctxt.isProcessorAvailable() == true &&msg.isValid() == true]// Next StateRunning// Actions{StopTimer("Idle");DoWork(msg);}Run(msg: const Message&)// Next State Actionsnil {RejectRequest(msg);}
}
Note:当使用转换guard和转换参数时,同一转换的多个实例必须具有相同的参数列表。就像c++和Java方法一样,Run(msg: const Message&)和Run()不是同一个转换。在使用多个gurad定义相同的转换时,如果不能使用相同的参数列表,将导致生成不正确的代码。
Tcl “arguments”:
虽然Tcl是一种无类型语言,但Tcl区分了按值调用和按引用调用。默认情况下,如果转换参数没有指定类型,SMC将生成按值调用的Tcl代码。但可以使用"value"或"reference"这些人为类型。
如果你的Tcl-targeted FSM有一个转换:
DoWork(task: value)Working{workOn(task);}
则生成的Tcl为:
public method DoWork {task} {workOn $this $task;
}
如果你的Tcl-targeted FSM有一个转换:
DoWork(task: reference)Working{workOn(task);}
则生成的Tcl为:
public method DoWork {task} {workOn $this task;
}
8、Entry 和 Exit动作
当转换离开某个状态时,它会在任何转换操作之前执行该状态的退出操作。当转换进入某个状态时,它执行该状态的进入操作。转换按以下顺序执行操作:
- “From”状态的退出动作。
- 将当前状态设置为空。
- 转换操作的顺序与.sm文件中定义的顺序相同。
- 将当前状态设置为“to”状态。
- “To”状态的进入动作。
// 状态
Idle //闲置
Entry {StartTimer("Idle", 1); CheckQueue();}//进入该状态时,执行该操作
Exit {StopTimer("Idle");} //离开该状态时,执行该操作
{//转换操作
}
从6.0.0版本开始,SMC生成一个enterStartState方法,该方法执行开始状态的进入动作。现在由应用程序在实例化有限状态机后调用start方法。如果不适合在启动时执行入口操作,则不要调用enterStartState。无需调用此方法来设置有限状态机的启动状态,这在FSM实例化时完成。此方法仅用于执行启动状态的进入操作。
如果要调用此方法,请确保在上下文类的构造函数之外调用。这是因为entry调用类方法。如果在上下文类的构造函数中调用enterStateState,则上下文实例将在完成初始化之前被引用,这是一件不好的事情。
enterStartState不防止被多次调用。它应该最多调用一次,并且在发出任何转换之前调用。不遵循这一要求可能会导致不适当的有限状态机行为。
是否执行状态的Entry和Exit操作取决于所采取的转换类型。下表显示了哪些转换执行“from”状态的Exit动作,哪些转换执行“to”状态的Entry动作。
转换类型 | 执行“From”状态的Exit动作? | 执行“To状态的”Entry动作? |
---|---|---|
Simple Transition | 是 | 是 |
External Loopback Transition | 是 | 是 |
Internal Loopback Transition | 否 | 否 |
Push 转换 | 否 | 是 |
Pop 转换 | 是 | 否 |
9、Push 转换
// SMC v1.3.2版本语法
Running
{Blocked BlockPop/push(WaitMap::Blocked) {GetResource();}
}
这将导致状态机:
-
转换到 BlockPop 状态。
-
执行 BlockPop entry 动作。
-
Push到 WaitMap::Blocked 状态。
-
执行 WaitMap::Blocked entry 动作。
当WaitMap发出pop转换时,控制权将返回到BlockPop,并且从这里发出pop转换。
当一个状态有两个不同的转换,这两个转换推送到相同的状态,但需要以不同的方式处理弹出转换时,使用这个新语法。例如:
Idle
{NewTask NewTask/push(DoTask) {}RestartTask OldTask/push(DoTask) {}
}NewTask
{TaskDone Idle {}// Try running the task one more time.TaskFailed OldTask/push(DoTask) {}
}OldTask
{TaskDone Idle {}TaskFailed Idle {logFailure();}
}
10、Pop转换
pop转换与push转换的不同之处在于:
- 未指定最终状态。这是因为pop转换将返回到发出相应推送的任何状态。
- pop转换有一个可选参数:转换名称 transition name。
在上面的例子中,如果资源请求被授予,则状态机返回到执行推送的相应状态,然后进行该状态的OK转换。如果请求被拒绝,除了采取FAILED转换外,还会发生相同的事情。对应的push转换代码为:
Running
{Blocked push(WaitMap::Blocked) {GetResource();}// Handle the return "transitions" from WaitMap.OK nil {}FAILED Idle {Abend(INSUFFICIENT_RESOURCES);}
}
从SMC v. 1.2.0开始,可以在pop转换的transition参数之后添加其他参数。这些附加参数与传递给操作的其他参数一样,将被传递到命名转换中。按照上面的例子,给定pop转换pop(FAILED, errorCode, reason),那么FAILED应该被编码为:
FAILED(errorCode: ErrorCode, reason: string)Idle{Abend(errorCode, reason);}
11、默认转换
如果一个状态接收到一个在该状态中没有定义的转换,SMC会有两个独立的机制来处理这种情况。
- “Default”状态。每个%map都可以有一个名为“Default”的特殊状态(注意D为大写)。与所有其他状态一样,默认状态包含转换
Default
{//有效的运行请求,但转换在无效状态下发生。对有效消息发送拒绝回复。Run(msg: const Message&)[ctxt.isProcessorAvailable() == true &&msg.isValid() == true]nil{RejectRequest(msg);}// 在无效状态下接收到的无效消息将被忽略。Run(msg: const Message&)nil{}ShutdownShuttingDown{StartShutdown();}
}
默认状态转换可能具有非默认转换的保护和参数特性。这意味着对于同一转换,默认状态可能包含多个受保护和一个不受保护的定义。
- “默认”转换。它被放置在状态中,用于备份所有转换。
Connecting
{// 现在连接到远端,可以登录了。ConnectedConnected{logon();}// 此时的任何其他转换都是错误的。// 请停止连接进程,稍后重试。DefaultRetryConnection{stopConnecting();}
}
因为任何转换都可以通过默认转换,所以默认转换:
-
可能没有参数列表。
-
默认转换可能需要一个guard。
-
将Default转换置于Default状态意味着将处理所有转换。
相关文章:

SMC状态机 讲解2 从模型到SMC
SMC状态机 讲解2 从模型到SMC 1、实例化有限状态机(FSM)2、简单转换 Simple Transition3、外部环回转换 External Loopback Transition4、内部环回转换 Internal Loopback Transition5、转换动作6、转换Guard7、转换参数8、Entry 和 Exit动作9、Push 转换10、Pop转换…...

MyBatis-Plus的使用
MyBatis-Plus 1、mybatis-plus介绍 官网:https://baomidou.com/ MyBatis-Plus (简称 MP)是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。MyBatis-Plus提供了通用的mapper…...

板卡设计+硬件每日学习十个知识点(44)23.8.24 (检测单元设计,接口部分设计,板卡电源输入设计,电源检测电路)
文章目录 1.检测单元介绍(使用GD32单片机)2.GD32的最小系统板3.GD32的温度监测4.GD32的电压监测和电流监测5.GD32的布线6.接口部分设计7.板卡电源输入设计8.电源检测电路 1.检测单元介绍(使用GD32单片机) 答: 首先要为…...

jmeter HTTP信息头管理器
首先,打开JMeter并创建一个新的测试计划。右键单击测试计划,选择"添加" > “线程组”,然后在线程组上右键单击,选择"添加" > “Sampler” > “HTTP请求”。 在HTTP请求中填写服务器的URL和其他必要…...
各种中间件的默认端口
面试时会忘记个别中间件端口 docker:2375 nacos:8848 redis:6379 rabbitMq: 5672(后台配置的端口)15672(web管理界面)账号:guest15674(web STOMP插件):通过WebSocket…...

leetcode303. 区域和检索 - 数组不可变(java)
前缀和数组的应用 区域和检索 - 数组不可变题目描述前缀和数组代码演示 区域和检索 - 数组不可变 难度 - 简单 原题链接 - 区域和检索 - 数组不可变 题目描述 给定一个整数数组 nums,处理以下类型的多个查询: 计算索引 left 和 right (包含 left 和 righ…...

PHP 安装Composer,vue前端依赖包
电脑安装Composer 官网下载:https://getcomposer.org/Composer-Setup.exe 后端安装: 检查是否安装依赖: 安装Composer install 或 Composer i 前端安装: yarn install 安装依赖...

OpenCV项目开发实战--基于Python/C++实现鼠标注释图像和轨迹栏来控制图像大小
鼠标指针是图形用户界面 (GUI) 中的关键组件。没有它,您就无法真正考虑与 GUI 进行交互。那么,让我们深入了解 OpenCV 中鼠标和轨迹栏的内置函数。我们将演示如何使用鼠标来注释图像,以及如何使用轨迹栏来控制图像的大小 我们将使用下图来演示 OpenCV 中鼠标指针和轨迹栏功能…...
❤ Vue使用Eslint检测报错问题和解决
❤ Vue使用Eslint检测报错问题和解决 1、 关闭Eslint检测 关闭ESLint语法检测即可:具体步骤如下: 第一步我们打开setting设置: 打开左上角的file,然后点击setting 接下来进入setting以后我们来看下面操作: eol-l…...

解决运行在微信小程序中报[ app.json 文件内容错误] app.json: app.json 未找到(env: Windows,mp,1.05.2204
找到project.config.json文件夹 添加 "miniprogramRoot": "unpackage/dist/dev/mp-weixin/", 即可...
python 基础 -- 安装Python模块
作为一个流行的开源开发项目,Python拥有一个由贡献者和用户组成的活跃支持社区,他们还根据开源许可条款向其他Python开发人员提供他们的软件。 这允许Python用户有效地共享和协作,从其他人已经创建的常见(有时甚至是罕见的!)问题的解决方案中…...

C语言实现状态机
关于状态机,基础的知识点可以自行理解,讲解的很多,这里主要是想写一个有限状态机FSM通用的写法,目的在于更好理解,移植,节省代码阅读与调试时间,体现出编程之美。 传统的实现方案 if...else : …...
交叉编译工具链arm-linux-gnueabihf的安装-ubuntu 20.04
前面下载安装步骤参考该博主的文章 http://t.csdn.cn/ZbjFX 另:本人对所遇到的环境变量的配置问题作补充 1.修改环境变量 建议直接在.bashrc文件作修改 ,修改方式相同 ( vi :视自己的编辑器而定) sudo vi ~/.bashrc 2.修改环境变量后,可…...
Java的类加载器
类加载 1、ClassLoader 用来加载 Class 文件 2、 系统内置的ClassLoader 通过双亲委托加载指定目录下的class和资源 3、 可以自定义ClassLoader 一般覆盖findClass() 4、ContextClassLoader 与线程相关,可以获取和设置,可以绕过双亲委托的机制。 三个类…...

Stable Diffusion web UI 部署详细教程
前言 本文使用 AutoDL 平台进行 Stable Diffusion web UI 云端部署 AutoDL 官网:AutoDL算力云 | 弹性、好用、省钱。租GPU就上AutoDL Stable Diffusion web UI 官网:AUTOMATIC1111/stable-diffusion-webui: Stable Diffusion web UI (github.com) 步…...

《深度学习计算机视觉 》书籍分享(包邮送书三本)
深度学习计算机视觉介绍 随着计算机技术的发展和进步,计算机视觉领域得到了广泛的关注和研究。而深度学习作为一种强大的机器学习方法,已经成为计算机视觉领域的重要工具之一。本文将介绍深度学习在计算机视觉中的应用和取得的成果。 深度学习是一种模…...

【使用 k 折叠交叉验证的卷积神经网络(CNN)】基于卷积神经网络的无特征EMG模式识别研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

微服务 Nacos配置热部署
在nacos中添加配置文件 在配置列表中添加配置, 注意:项目的核心配置,需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。 从微服务拉取配置 微服务要拉取nacos中管理的配置,并且与…...

国产调度器之光——Fsched到底有多能打?
这是一篇推荐我们速石自研调度器——Fsched的文章。 看起来在专门写调度器,但又不完全在写。 往下看,你就懂了。 本篇一共五个章节: 一、介绍一下主角——速石自研调度器Fsched 二、只要有个调度器,就够了吗? 三…...
LeetCode:53. 最大子数组和 - Python
53. 最大子数组和 问题描述: 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的一个连续部分。 示例 1: 输入:nums [-…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...

排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...