85、UML 动作语义与调用动作的深入解析

UML 动作语义与调用动作的深入解析

1. 运行时线程与令牌的定义

在活动执行期间, SchedulerThread ⊆ UTHREAD 用于表示运行时线程。令牌 t ∈ Token 被定义为一个 4 元组 t = (id, thread, sittingOn, cameFrom) ,其中:
- id ∈ String 是唯一标识符。
- thread ∈ SchedulerThread 是与此令牌关联的运行时线程。
- sittingOn ∈ GraphNode 是此令牌所在的活动节点。
- cameFrom ∈ GraphNode 是此令牌发送来源的活动节点。

调度线程 th ∈ SchedulerThread 被定义为一个对 th = (id, token) ,其中:
- id ∈ String 是唯一标识符。
- token ∈ Token 是与此线程关联的令牌。

Tokens 是状态 s 中存在的令牌集合,且 Token = ⋃s∈USTATE Tokens 。一般来说, Tokens ⊆ s.cs.pc ;但在处理活动图时,令牌是唯一的程序计数器,因此 Tokens = s.cs.pc 。类似地, SchedulerThreads ⊆ s.cs.thr 一般成立,在处理活动时, SchedulerThreads = s.cs.thr

令牌和调度线程是唯一配对的,即每个令牌都有一个关联的调度线程,反之亦然:

(∀t ∈ Token | ∃!th ∈ SchedulerThread | t.thread = th ∧ th.token = t)
∧ (∀th ∈ SchedulerThread | ∃!t ∈ Token | th.token = t ∧ t.thread = th)

2. UML 动作的语义

2.1 动作的基本概念

执行中的 UML 模型被视为一个大型状态机。单个 UML 动作就像可执行的编程语言语句,在执行时修改底层状态。每个动作可能有属性和关联,用于为动作提供静态信息,例如 CreateObjectAction 要使用的分类器类型。此外,动作可能有输入和/或输出引脚,用于动态操作,例如输出引脚会保存 CreateObjectAction 的结果对象。

活动用于将单个动作组合成更大的执行单元。我们将活动描述为有向图;每个图节点 gn ∈ GraphNode 代表 UML 活动中的某个概念,例如表示特定 UML 动作的动作节点或表示分叉的控制节点等。

2.2 活动的执行与状态变化

一个活动可以调用其他活动。执行这样一组活动包括在对应活动的有向图中找到合适的路径。当遍历/执行每个图节点时,底层状态会发生变化。例如,执行初始节点会将控制令牌传递到初始节点的目标节点。执行动作节点(表示特定 UML 动作的图节点)会根据动作的类型以及该动作的属性、关联和输入对状态进行各种更改。UML 中总共定义了 45 个动作,其中 36 个是具体动作。到目前为止,我们已经形式化了 22 个具体动作,如下表所示:

Action ds cs es vars pc/th ad
AcceptCallAction
AcceptEventAction
AddStructuralFeatureValueAction
AddVariableValueAction
CallBehaviorAction
CallOperationAction
ClearStructuralFeatureAction
ClearVariableAction
CreateObjectAction
DestroyObjectAction
ReadExtentAction
ReadIsClassifiedObjectAction
ReadSelfAction
ReadStructuralFeatureAction
ReadVariableAction
RemoveStructuralFeatureValueAction
RemoveVariableValueAction
ReplyAction
SendSignalAction
StartClassifierBehaviorAction
TestIdentityAction
ValueSpecificationAction

2.3 动作节点和动作的定义

动作节点 an ∈ ActionNode 是一个 8 元组。在本文中,我们只关注其四个项: action ∈ Action (指节点表示的特定 UML 动作), in, out ⊆ GraphNode (此节点的源节点和目标节点集合),以及 annot ⊆ Annotation (表示此节点上的注释集合,这些注释提供信息以填充动作的属性和关联)。

动作 a ∈ Action 被定义为一个 4 元组 a = (name, inPins, outPins, attrs) ,其中 name ∈ String 是动作的名称,例如 “CreateObjectAction”。 inPins, outPins ⊆ String × UVAL 分别是输入和输出引脚。最后, attrs ⊆ String × (UVAL ∪ UVAR ∪ UTYPE) 是动作的属性和关联集合。

2.4 示例映射:AddStructuralFeatureValueAction

AddStructuralFeatureValueAction 为例,我们使用系统模型作为基本语义域,通过明确识别表示每个特定动作的动作节点执行时底层状态 s = (ds, cs, es) 如何变化,来正式定义单个 UML 动作行为的语义。

asfva 是表示 AddStructuralFeatureValueAction 实例的动作节点。我们通过定义一个函数 [[asfva]] : USTATE → USTATE 来解释执行 asfva 的效果,使得对于 (ds, cs, es) ∈ USTATE [[asfva]](ds, cs, es) 定义如下:

前置条件 :动作节点 asfva 已启用并已被调度器选中触发。

后置条件 :如果满足前置条件,则 [[asfva]](ds, cs, es) = (ds′, cs′, es′) ,其中:
- ds′ = setval(ds, oid, at, v)
- cs′ = advance(cs, asfva)
- es′ = es

其中:
- setval : DataStore × UOID × UVAR × UVAL → DataStore 定义为 setval((o, m), oid, at, v) = (o, m ⊕ [∗oid.at = v])
- oid ∈ UOID 是其属性将被修改的对象标识符, ("object", oid) ∈ asfva.action.inPins
- at ∈ UVAR 是要修改的属性, ("structuralFeature", at) ∈ asfva.action.attrs
- v ∈ UVAL 是属性的新值, ("value", v) ∈ asfva.action.inPins
- 是扩展映射的运算符,例如 f ⊕ [a = b] 通过将 a 映射到 b 来扩展 f
- 是解引用运算符,对象标识符 oid 是对记录的引用, ∗oid 是该记录。
- advance : ControlStore × GraphNode → ControlStore 定义为 advance((ad, pc, thr, vars), gn) = (ad, pc′, thr ′, vars)
- 新的程序计数器集合是旧集合减去当前执行节点上的任何令牌,再加上当前节点每个真实目标的新令牌,即 pc′ = pc \ removed ∪ added
- removed = {t ∈ pc | t.sittingOn = gn}
- added = {t ∈ Token \ pc | t.cameFrom = gn ∧ ∃!n ∈ gn.realOut | t.sittingOn = n}
- 新线程集合中的所有线程与新的令牌集合匹配, th′ = {t ∈ SchedulerThread | t.token ∈ pc′}

3. 状态变化总结

从表 1 可以得出以下关于 UML 动作的观察:
- 任何动作的执行至少会导致控制存储的程序计数器和线程的推进。
- 一些动作只导致控制存储的程序计数器和线程的变化,不影响其他状态部分,这些动作本质上是“读取”操作,例如 ReadVariableAction 。此外,一些动作从整个系统模型中读取信息,而不是从数据存储中读取,例如 ValueSpecificationAction 从全局获取值, TestIdentityAction 比较两个值等。
- 一些动作在执行时需要其上下文信息,在 ad 列中标记为 。例如, ReadSelfAction 返回拥有该动作所在活动的对象的标识符,为此,该动作需要导航到其周围的活动图,进而找到图的拥有对象。
- 一些动作不读取其上下文信息,而是修改其上下文,即当前正在执行的活动图集合。例如, CallOperationAction CallBehaviorAction StartClassifierBehaviorAction 都引用可能包含在单独活动图中的行为,在执行调用时,会将附加图合并到集合 ad 中。
- 一般来说,大多数动作是“特定的”,只修改状态的一部分。例如,结构特征动作只修改数据存储,变量动作只修改控制存储的 vars 部分等。
- 到目前为止,我们只确定了两个“非特定”动作,它们除了推进程序计数器和线程外,还影响状态的两个或更多区域。 CallOperationAction 修改当前活动集合 ad (通过添加被调用的活动)和事件存储 es (通过处理调用消息)。 DestroyObjectAction 从数据存储中移除一个对象,并从事件存储中移除其附带的事件缓冲区。
- 大多数动作可以被认为是“单步”的,即动作的执行会导致状态变化,之后无需再次访问该动作。相比之下,“多步”动作必须被访问两次才能完全完成其执行。例如,当 CallOperationAction CallBehaviorAction 同步使用时,调用动作的执行在被调用的行为(例如另一个活动)完全执行之前不被认为完成。但并非所有调用动作都是多步的,这些调用动作可以异步执行,即被调用的行为被添加到当前活动集合中,然后调用被认为完成。类似地,发送/广播动作从不等待回复。

4. 调用动作的实用主义

4.1 调用动作的复杂性

大多数 UML 动作很直接,例如 CreateObjectAction 创建新的对象标识符, ReadVariableAction 读取变量等。然而,调用动作可能相当深奥。UML 中有很多用于调用行为的动作,在建模活动时确定使用哪个动作可能相当复杂。

4.2 调用动作的分类

调用动作根据两个维度进行分类:调用是直接还是间接,以及被调用的行为是同步还是异步执行。

4.2.1 直接调用
  • CallBehaviorAction with isSynchronous = false :此动作用于直接调用行为,不使用消息或信号传递。目标行为中不需要接受动作。异步的 CallBehaviorAction 在其被调用的“行为开始,或者至少确保在某个时刻开始”时被认为完成。
  • StartClassifierBehaviorAction :虽然技术上不是调用动作(它不继承自 InvocationAction ),但该动作“启动输入对象的分类器行为”。没有消息或信号,目标对象必须执行该行为,因此这是直接调用。它是异步的,因为调用行为在分类器行为被调用后继续执行。
  • CallBehaviorAction with isSynchronous = true :同步使用时, CallBehaviorAction “等待被调用的行为执行完成,并在其输出引脚上返回结果”。
4.2.2 间接调用
  • CallOperationAction with isSynchronous = false :这是一个间接调用动作,它“向目标对象发送操作调用请求,可能会导致所需行为的调用”。异步使用时,调用行为在发送调用请求后可以继续执行。在接收端, AcceptEventAction 设计用于接受异步调用,但 AcceptCallAction 也可以使用,我们更倾向于使用 AcceptCallAction ,以便同一目标活动可以处理同步和异步调用。
  • SendSignalAction :此动作创建一个信号并将其传输到目标对象,可能会导致行为的调用。调用行为继续执行,在接收端需要一个 AcceptEventAction
  • SendObjectAction :类似于 SendSignalAction ,此动作将一个对象传输到目标对象,可能会调用行为。调用行为继续执行。
  • BroadcastSignalAction :此动作与 SendSignalAction 相同,只是信号发送到多个目标,可能会调用行为。
  • CallOperationAction with isSynchronous = true :同步使用时, CallOperationAction 必须在接收端由 AcceptCallAction 接受,该动作将与 ReplyAction 关联。 ReplyAction 完成调用的执行,将结果返回给调用者,然后调用者可以终止。

调用动作的分类总结如下表:
| 调用方式 | 异步 | 同步 |
| — | — | — |
| 直接 | 1. CallBehaviorAction isSynchronous = false
2. StartClassifierBehaviorAction | 3. CallBehaviorAction isSynchronous = true |
| 间接 | 4. CallOperationAction isSynchronous = false
5. SendSignalAction
6. SendObjectAction
7. BroadcastSignalAction | 8. CallOperationAction isSynchronous = true |

4.3 调用动作的流程图

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([开始]):::startend --> B{调用方式}:::decision
    B -->|直接| C{同步性}:::decision
    B -->|间接| D{同步性}:::decision
    C -->|异步| E(CallBehaviorAction isSynchronous = false):::process
    C -->|同步| F(CallBehaviorAction isSynchronous = true):::process
    D -->|异步| G(CallOperationAction isSynchronous = false):::process
    D -->|同步| H(CallOperationAction isSynchronous = true):::process
    E --> I(执行并继续):::process
    F --> J(等待结果):::process
    G --> K(发送请求后继续):::process
    H --> L(等待接受和回复):::process
    I --> M([结束]):::startend
    J --> M
    K --> M
    L --> M

这个流程图展示了调用动作根据调用方式(直接或间接)和同步性(异步或同步)的分类,以及不同调用动作的执行流程。

5. 相关工作

5.1 学术和商业工具中的动作语言

UML 规范定义了动作语义,但没有定义动作的具体语法。任何可执行的 UML 基础都必须配有动作语言。我们主要关注 UML 动作的形式语义,为了研究动作的执行,我们使用 UML 活动作为动作语言来将动作“粘合”在一起。

学术动作语言往往是专注于模型分析工具的一部分。OxUML 是一种基于 OCL 的动作语言,支持有副作用的动作,其结果是一个由 UML 虚拟机支持的可执行 UML。有研究提出了 UML 的一个配置文件,提供“完整而精确的面向方面的行为建模”,包括 UML 的动作语义,在编织后可以执行完整模型以观察建模方面的行为。ActiveChartsIDE 是 Microsoft Visio 的一个插件,带有支持活动图模拟和调试的解释器。

有几个商业工具支持可执行 UML,每个工具都包含自己的专有动作语言。xUML 是 UML 的一个子集,由 Kennedy - Carter 在其 iUML 工具中使用,它包含动作规范语言并允许构建可执行模型。xtUML 使用对象动作语言,由 Mentor Graphics 的 BridgePoint 工具套件实现。还有一个用于 IBM 的 Rational 建模工具的插件,使用状态机和活动“启用 UML 模型的执行、调试和测试”,该执行引擎不专门支持 UML 动作,而是使用 Java 作为动作语言。

5.2 现有工作的不足

尽管可执行 UML 需要包含某种动作语言,但目前介绍的相关工作都没有专注于单个 UML 动作。这些举措都使用了更高级别的动作语言,而且据我们所知,这些动作语言都没有形式语义。

定义 UML 活动的语义是一个活跃的研究领域,但由于 UML 2 的引入使活动有了很大变化,研究范围有所缩小。例如,有研究为旧版本的 UML 动作提供语义,但由于后来引入了引脚,这些研究已过时。另一方面,有基于几种形式主义(如抽象状态机、Petri 网和动态元建模)来定义 UML 2 活动语义的研究,还有专注于活动模型检查的研究,但这些研究都不支持单个 UML 动作。

5.3 相关提交与我们的研究重点

目前,OMG 收到了一份关于可执行 UML 基础的提交,该提交定义了可执行 UML 的基础子集(fUML),并得到了许多建模技术领域知名企业的支持。我们对动作语义的研究与这份提交最相关,但我们不太关注产生 UML 的“紧凑”子集。例如,我们能够支持调用,因此支持 AcceptCallAction ReplyAction

5.4 现有研究对比总结

为了更清晰地对比现有研究与我们工作的差异,下面通过表格进行总结:
| 研究类型 | 动作语言 | 是否专注单个 UML 动作 | 是否有形式语义 | 对调用动作支持情况 |
| — | — | — | — | — |
| OxUML | 基于 OCL | 否 | 无 | 未提及 |
| 某 UML 配置文件研究 | 未明确 | 否 | 无 | 未提及 |
| ActiveChartsIDE | 未明确 | 否 | 无 | 未提及 |
| xUML | 动作规范语言 | 否 | 无 | 未提及 |
| xtUML | 对象动作语言 | 否 | 无 | 未提及 |
| IBM Rational 插件 | Java | 否 | 无 | 未提及 |
| 我们的研究 | UML 活动 | 是 | 有 | 支持 AcceptCallAction ReplyAction |

从这个表格可以看出,我们的研究在专注单个 UML 动作和提供形式语义方面具有独特性,并且在调用动作的支持上也有自己的特点。

5.5 未来研究展望

虽然我们已经在 UML 动作语义的研究上取得了一定进展,但仍有许多工作可以进一步开展。
- 动作语义的完善 :目前只形式化了 22 个具体动作,还有 14 个具体动作以及 9 个非具体动作的语义需要进一步研究和形式化,以实现对 UML 动作语义的全面覆盖。
- 复杂调用场景的处理 :虽然对调用动作进行了分类和分析,但对于更复杂的调用场景,如嵌套调用、循环调用等,还需要深入研究其语义和执行机制。
- 与其他技术的结合 :可以考虑将 UML 动作语义与其他软件开发技术,如人工智能、大数据等相结合,探索新的应用领域和开发模式。

6. 总结

6.1 UML 动作核心要点回顾

  • 运行时概念 :定义了调度线程和令牌,它们之间存在唯一配对关系,用于表示活动执行期间的运行时状态。
  • 动作语义 :UML 动作是可执行的,能修改底层状态,活动通过有向图组合动作,不同动作的执行会导致状态的不同变化。
  • 调用动作 :分为直接调用和间接调用,以及同步和异步执行方式,不同调用动作有不同的执行流程和特点。

6.2 研究意义与价值

我们的研究为 UML 动作提供了形式化的语义,有助于更准确地理解和执行 UML 模型。通过对单个 UML 动作的研究,能够更好地支持复杂系统的建模和开发,特别是在处理调用动作方面,为软件开发中的行为调用提供了清晰的语义和执行规则。

6.3 研究成果的应用前景

  • 软件开发 :在软件开发过程中,使用我们研究的 UML 动作语义可以提高模型的可执行性和准确性,减少开发过程中的错误和歧义。
  • 模型验证与测试 :形式化的语义可以为模型验证和测试提供基础,通过对动作执行结果的验证,确保模型的正确性。
  • 教育与培训 :对于 UML 学习和培训来说,清晰的动作语义和执行规则有助于学习者更好地理解和掌握 UML 的核心概念和应用。

6.4 研究的局限性与改进方向

虽然我们的研究取得了一定成果,但也存在一些局限性。例如,目前只考虑了部分 UML 动作,对于一些复杂的动作和场景还需要进一步研究。未来可以扩大研究范围,完善动作语义的形式化定义,提高研究的完整性和实用性。

通过以上对 UML 动作语义和调用动作的研究,我们希望能够为 UML 的发展和应用提供有益的参考和支持,推动软件开发技术的不断进步。

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([开始研究]):::startend --> B(定义运行时概念):::process
    B --> C(研究动作语义):::process
    C --> D(分析调用动作):::process
    D --> E(对比相关工作):::process
    E --> F(总结研究成果):::process
    F --> G(提出未来展望):::process
    G --> H([结束研究]):::startend

这个流程图展示了我们研究的整体流程,从开始研究到最终提出未来展望,涵盖了研究的各个关键步骤。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值