“检查线性一致性时,可先从内部执行投影出接口历史,再寻找满足顺序规格的线性化。验证时序性质时,则把完整执行解释为轨迹或路径。每一步都应说明保留了哪些事件和顺序。”
形式陈述
路径先于轨迹
给定标号转移系统
路径保留内部状态和每一步的动作标签。有限路径有最后状态;无限路径包含可数无限多步;若一条有限路径的末状态无后继,它是最大路径。分析持续服务时通常关心无限路径,分析会终止的程序时则不能把有限最大路径丢掉。
动作轨迹先忘掉状态:
给定观察映射
并发对象历史只记录接口调用与返回;LTS 路径还保留系统内部状态与动作。把一条路径投影到接口事件可以得到历史,但多个不同的内部路径可能产生同一接口历史,因此它不能唯一恢复隐藏的执行细节。这里的全序步骤枚举是调度交错,不是已经完成了对象正确性意义上的线性化证明。
行为集合与前缀
系统的路径语义和轨迹语义分别是它允许的路径集合与轨迹集合:
若只收集有限前缀,则每条轨迹的每个有限前缀也在集合中,形成 prefix-closed 语义。这非常适合安全性:一旦坏事发生,某个有限前缀已经足以见证违反。活性通常需要完整无限行为,因为任意有限前缀仍可能在未来兑现承诺。
有限轨迹集合是否包含非最大前缀必须明确。把“用户发出请求”这一半截执行算作系统完成行为,和仅把它算作可继续前缀,会得到不同的 refinement 与测试结论。
直觉
隐藏内部步骤的例子
设服务收到 request 后有两条内部路径:缓存命中时执行 reply。完整路径可以是
或
删除内部标签后,两条路径都有可见轨迹 request reply。若 fast-renew,而 slow-renew,当前短轨迹仍看不出这项分支差异;观察更长轨迹才可能区分。
相同轨迹也可能掩盖分支时机。系统
但
例子与边界
投影、隐藏与重命名
给定可观察动作集
这些操作必须作用于整条行为并尊重顺序。仅比较“出现过哪些动作”的集合会丢失先后与重复次数,例如 open close 和 close open 拥有相同动作种类,却显然不是同一轨迹。
投影也不总与最大性相容。比较两条完整行为:一条在 request reply 后正常结束,另一条在同样两个可见动作后无限执行 request reply,但后一条路径从未终止。这种无限内部执行称为发散;若语义需要区分它与正常终止,就必须额外记录完成或发散信息。
状态轨迹与停顿
若状态带原子命题标记
连续若干状态可能拥有同一可观察标记。停顿等价允许把每个相同标记块作有限次重复,同时保持块的次序。比如
这里不能把“有限次重复”扩展成无限等待。
路径语义不会自动规定公平性。一个始终使能却永不执行的动作,仍可能出现在系统允许的无限路径中;要排除这种调度,需要另加公平性约束。把期望的公平路径直接从例子中挑出来,会把规格假设伪装成模型事实。
推论与应用
语义边界与使用方式
轨迹等价只比较所选观察接口下的行为集合。接口变粗,更多实现会变得等价;接口变细,原先隐藏的状态、时间或失败原因会重新可见。行为精化常写成
表示实现没有产生规格禁止的可见序列。任何这类结论都要同时给出动作字母表、隐藏集合和有限/无限语义;轨迹包含不会自动保持死锁自由、发散敏感性或分支结构。若这些也属于合同,应改用带 failures/divergence 的语义或更强的模拟关系。
时序逻辑在这些执行序列上解释“最终”“始终”“直到”;反例与见证轨迹把逻辑失败还原成一条可读行为。逻辑是对行为集合提出性质,不替代本页对行为本身的定义。
若要求同一公开输入的不同运行给出相同公开输出,检查对象就是两条轨迹之间的相容关系。这属于超性质:它直接约束整套轨迹集合,不能当作一个逐轨迹解释的 LTL 公式来检查。
当合同允许非确定输出、只要求不同秘密输入具有相同的可能输出集合时,公开投影可能过早遗忘所需的信息。有限运行匹配例子保留每条完整运行的秘密输入标签,然后在相同公开输入下要求每次运行都存在一个输出相同的匹配运行。两个程序可以拥有相同的公开轨迹并集,却有不同的按秘密索引的输出集合;观察投影和规格量词的解释域必须分别写清。
参考资料
- C. A. R. Hoare, Communicating Sequential Processes, Prentice Hall, 1985, Chs. 1–3。
- Robin Milner, Communication and Concurrency, Prentice Hall, 1989, Chs. 2–5。
- Christel Baier and Joost-Pieter Katoen, Principles of Model Checking, MIT Press, 2008, §§2.1–2.3, 3.2。