当前位置: 首页 > news >正文

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

Simple Transition

// State
Idle
{// 转换到下一个状态的动作Run        Running        {}
}

状态和转换名称的命名规则必须为“[A- za -z_][A- za -z0-9_]*”形式。

3、外部环回转换 External Loopback Transition

在这里插入图片描述

// State
Idle
{// 转换到下一个状态的动作Timeout    Idle           {}
}

外部环回确实离开当前状态并返回到当前状态。这意味着执行状态的exitentry操作。这与内部环回转换相反。

4、内部环回转换 Internal Loopback Transition

在这里插入图片描述

// 状态
Idle
{// 转换到下一个状态的动作Timeout    nil            {}
}

使用“nil”作为下一个状态将导致转换保持在当前状态,而不是离开它。这意味着状态的退出和进入操作不会被执行。这与外部环回转换相反。

5、转换动作

在这里插入图片描述

// 状态
Idle
{//转换Run// 下一个状态Running// 动作{StopTimer("Idle");DoWork();}
}
  1. 转换的动作必须包含在“{}”中。
  2. 动作的形式为“[A-Za-z] [A-Za-z0-9_ -] *()”。参数列表(argument list)必须为空或由逗号分隔的字面值组成。例如:整数(正数或负数、十进制、八进制或十六进制)、浮点数、双引号括起来的字符串、常量和转换参数。
  3. 操作必须是%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,则发生以下情况之一(按优先级排序):

  1. 如果状态有另一个具有相同名称和参数的受保护转换,则检查该转换的保护。
  2. 否则,如果状态有另一个具有相同名称和参数列表的未保护转换,则进行该转换。
  3. 如果以上都不是,则遵循默认的转换逻辑。

一个状态可以有多个具有相同名称和参数列表的转换,只要它们都有唯一的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动作

在这里插入图片描述

当转换离开某个状态时,它会在任何转换操作之前执行该状态的退出操作。当转换进入某个状态时,它执行该状态的进入操作。转换按以下顺序执行操作:

  1. “From”状态的退出动作。
  2. 将当前状态设置为空。
  3. 转换操作的顺序与.sm文件中定义的顺序相同。
  4. 将当前状态设置为“to”状态。
  5. “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();}
}

这将导致状态机:

  1. 转换到 BlockPop 状态。

  2. 执行 BlockPop entry 动作。

  3. PushWaitMap::Blocked 状态。

  4. 执行 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转换的不同之处在于:

  1. 未指定最终状态。这是因为pop转换将返回到发出相应推送的任何状态。
  2. 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会有两个独立的机制来处理这种情况。

  1. “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();}
}

默认状态转换可能具有非默认转换的保护和参数特性。这意味着对于同一转换,默认状态可能包含多个受保护和一个不受保护的定义。

  1. “默认”转换。它被放置在状态中,用于备份所有转换。
Connecting
{// 现在连接到远端,可以登录了。ConnectedConnected{logon();}// 此时的任何其他转换都是错误的。// 请停止连接进程,稍后重试。DefaultRetryConnection{stopConnecting();}
}

因为任何转换都可以通过默认转换,所以默认转换:

  1. 可能没有参数列表。

  2. 默认转换可能需要一个guard。

  3. 将Default转换置于Default状态意味着将处理所有转换。

http://www.lryc.cn/news/138501.html

相关文章:

  • MyBatis-Plus的使用
  • 板卡设计+硬件每日学习十个知识点(44)23.8.24 (检测单元设计,接口部分设计,板卡电源输入设计,电源检测电路)
  • jmeter HTTP信息头管理器
  • 各种中间件的默认端口
  • leetcode303. 区域和检索 - 数组不可变(java)
  • PHP 安装Composer,vue前端依赖包
  • OpenCV项目开发实战--基于Python/C++实现鼠标注释图像和轨迹栏来控制图像大小
  • ❤ Vue使用Eslint检测报错问题和解决
  • 解决运行在微信小程序中报[ app.json 文件内容错误] app.json: app.json 未找到(env: Windows,mp,1.05.2204
  • python 基础 -- 安装Python模块
  • C语言实现状态机
  • 交叉编译工具链arm-linux-gnueabihf的安装-ubuntu 20.04
  • Java的类加载器
  • Stable Diffusion web UI 部署详细教程
  • 《深度学习计算机视觉 》书籍分享(包邮送书三本)
  • 【使用 k 折叠交叉验证的卷积神经网络(CNN)】基于卷积神经网络的无特征EMG模式识别研究(Matlab代码实现)
  • 微服务 Nacos配置热部署
  • 国产调度器之光——Fsched到底有多能打?
  • LeetCode:53. 最大子数组和 - Python
  • 网站建设 之 react usestate
  • 第一讲使用IDEA创建Java工程——HelloWorld
  • BootstrapBlazor组件使用:数据注解
  • MySQL 触发器
  • DPDK主从进程模式 rte_mempool_put失败
  • ZooKeeper 的工作原理
  • 【业务功能篇73】分布式ID解决方案
  • Qt安卓开发经验技巧总结V202308
  • 【vue2】前端实现下载后端返回的application/octet-stream文件流
  • 【Java】SM2Utils(国密 SM2 工具类)
  • 『C语言入门』初识C语言