当离开转换的两个保护条件都为假时,状态机将何去何从?

Where does a State machine go when both guard conditions on leaving transitions are false?

提问人:Dirk Fraanje 提问时间:10/24/2023 更新时间:10/28/2023 访问量:79

问:

我正在为下周一的 UML 考试练习,问题是下图的结果是什么,我认为该图无效,因为 x 的值第一次正好是 9。守卫是:大于 9 和 10 或更大。所以两个守卫都不是真的,因为守卫(+1)之后的效果是在评估守卫之后运行的。是我遗漏了什么,还是这确实不严谨:

State diagram valid?

我认为该图无效,因为两个防护装置都是错误的。

状态 UML 状态机 效应

评论

0赞 qwerty_so 10/26/2023
您的图表令人困惑,因为状态中的所有线都无效。它们没有退出行为,x 的递增是在转换中完成的。还是意味着退出行为是语句?x=x+1x=x+1
0赞 qwerty_so 10/26/2023
回答你的问题:无处可去。它将保持在没有自由过渡的最后一种状态。你是否认为这是错误的取决于要求。
0赞 Christophe 10/28/2023
我用其他发现更新了我的答案。如果得到您的考试结果的证实,将会很感兴趣;-)

答:

3赞 Christophe 10/25/2023 #1

编辑 - 最终(但很长)的答案

这个边缘案例中的关键问题

通常,操作会在离开状态之前清理情况。因此,在现实生活中,执行可能影响转换的清理操作并不常见。exit

假设 x 是任何其他并发状态机都无法访问的属性,我们可以按照图看到机器进入第一个状态,x 依次为 0、2、4、6,直到它以 x=8 进入具有两个传出转换的状态。

极端情况是该动作可能会对防护装置的状况产生影响。关键问题是,防护装置是在退出行为之前还是之后进行评估:exit

  • 如果在退出状态之前评估了守卫,则 x 为 8,并且为 true,并且过渡点火。[x<9]
  • 如果在退出状态后评估守卫,则 x 为 9,并且两个守卫都是假的,这意味着该状态不会退出,因此 X 将停留在 8,游戏永远结束。

非权威答案

不幸的是,UML 规范在这方面并不是非常清楚。我本来希望有一个关于何时评估警卫的明确声明,但这些信息被稀释了几个段落,并受到不同的解释(参见与qwerty_so交换的评论)。

因此,我最终看了《UML用户指南》,这本书并不具有权威性,也不再与最新的UML规范保持一致,但它的优点是,在OMG将其变得非常抽象之前,UML的发明者写得非常清楚。

他们传达的信息很明确:当收到与转换匹配的 trigerring 事件时,将对过渡防护进行评估。这意味着在行为之前对其进行评估,符合qwerty_so公开的逻辑。exit

当没有指定触发事件时,问题仍然存在,尽管我们可以理解它与状态准备退出有关。

规格怎么说

UML 2.5.1 规范的寻呼机 315 我们读到:

过渡可能具有关联的保护约束。具有计算结果为 false 的防护的转换将被禁用。

但是,什么是启用的过渡?UML 规范在有关运行完成的部分中要求几个条件,特别是:

(...)至少存在一条从源状态配置到目标状态配置或 (...) 的完整路径,其中所有保护条件均为 true

从源到目标的完整路径需要离开状态。UML 2.5.1 规范的 P 311/312 对此进行了解释:

无论 State 如何退出,只有在 State 的退出行为(如果已定义)完成执行后,StateMachine 才会被视为“离开”了该状态。

因此,这意味着没有启用的路径,因为退出意味着 x 为 9,并且两个防护的计算结果都为 false。这是我最初回答的结论。但是与用户指南的矛盾让我睡不着觉。

读了又读,终于找到了另外两个相关的段落。第一个部分解释了在未指定触发事件时无保护的简单转换的情况(P.314):

一种特殊的过渡是完成过渡,它有一个隐式触发器。启用此触发器的事件称为完成事件,它表示与完成转换的源状态关联的所有行为都已完成执行。对于简单状态,当关联的条目和 doActivity 行为完成执行时,将生成完成事件。

上面这一段的关键是,在完成状态时没有提到。这允许我与 UML 用户指南建立链接:触发转换的事件是当 和 完成时,与 无关。exitentrydoexit

关于守卫的另一段提到了复合过渡。我最初认为“复合跃迁”指的是一种具有子状态机或复合状态的特殊情况,这与我们的情况无关:

启用包含防护的复合转换之前,将对防护进行评估,除非它们位于源自选择伪态的转换上。在后一种情况下,当到达选择点时评估防护装置。

然而,“复合转换”似乎对应于机器在两个稳定配置之间的遍历。还解释了复合过渡的情况之一是完成过渡:

如果我们将两者放在一起,这意味着在退出行为之前评估防护。这很复杂,但很明确,并且覆盖了我之前基于“完整路径”的互操作。

结论

你的机器会用守卫 x<9 触发过渡,然后再做另一个循环,然后用 >=10 触发过渡,最后到达终点。

在这件事上,规格非常难以阅读。诚然,它们涵盖了广泛的案例,但已经有一个注释(表明它不够清楚)。本说明应予修改:

过渡防护装置

过渡可能具有关联的保护约束。具有计算结果为 false 的防护的转换将被禁用。在启用包含防护的复合转换之前,将对防护进行评估,除非它们位于源自选择伪态的转换上。在后一种情况下,当到达选择点时评估防护装置。没有关联防护的过渡将被视为具有始终为 true 的防护。

注意。完成转换也可能具有保护,在这种情况下,独立于退出行为评估保护

评论

0赞 qwerty_so 10/26/2023
请参阅我对 OP 的评论。 可能 x+1 被执行了两次。
0赞 Christophe 10/26/2023
@qwerty_so 我用狂野的格式理解“exit / x = x+ 1”,因为单独的 x+1 和空的显式退出似乎没有意义。事实上,在每次转换时,它都会执行两次:一次用于退出,一次用于过渡执行。但是,在它保持空闲状态的最后一个陈述中,它会被执行两次吗?
0赞 qwerty_so 10/26/2023
0;2;4, 6;8;10;12;14;16;最后 18 是你会拥有的.x
1赞 Christophe 10/27/2023
@qwerty_so 当进入第一个状态时,我发现 0,然后进入具有两个输出边的状态时,我发现 2、4、6,最后是 8。然后它被卡住了,因为退出状态会导致 x 为 9,这使得两个守卫都是假的,并且没有触发转换。所以状态不能退出,x 保持 8
1赞 Christophe 10/28/2023
@qwerty_so我花了一段时间来剖析标准并组装零件。现在编辑,我巩固你的立场。答案要长得多,因为我真的很想让它得到规范参考的支持。
1赞 qwerty_so 10/27/2023 #2

这是对克里斯托夫回答的修正(因为太长了,无法发表评论)。

事实上,UML 规范对保护/退出行为并不明确。但是,只有当状态可以退出时,才能执行退出行为。这意味着守卫已被证明是正确的(如果只有守卫出口)。因此,当双出口状态为 x==8 时,保护 x<9 将应用并且状态离开,从而递增 x 2 倍。当它下次以 x==16 进入时,防护 x>=10 适用。

评论

0赞 qwerty_so 10/27/2023
我想对于OP的考试来说,这里的所有答案都来得太晚了......
1赞 Christophe 10/27/2023
有趣。对你来说,“可以退出”没有考虑到退出行为,而我将其视为启用所需路径的一部分。我既不能否认也不能证实这种解释。至少我们同意规格的模糊性;-)幸运的是,现实生活中没有这种极端的边缘情况。也许UML规范应该像C++标准一样,添加一个关于“未定义行为”的部分;-)我仍然想知道 Axel 或 Geert 是否会带着我们俩都错过的晦涩的引述或脚注出现......
0赞 qwerty_so 10/28/2023
@Christophe 当然。如果“可以退出”对触发它造成副作用,它应该如何工作?这应该在规范中详细说明。有没有人发送错误报告(我的错误报告总是搁置很长时间......