“在 并发分离逻辑 中,传递一个地址值与传递该地址指向资源的访问权是两件事。设消息谓词 $M(v)$ 描述随值 $v$ 移动的资源;除显式参数 $v$ 外,它只依赖不被命令修改的逻辑参数,不再…”
形式陈述
并行规则与安全执行
并发分离逻辑在资源上下文
分离合取
该规则通常证明部分正确性与安全执行:若两边从分离资源出发且各自局部安全,那么任意合法交错不会因越权解引用而 fault,终止时资源仍可重新组合。精确结论依所选语言的 allocation、deallocation、并发读写和故障语义而定。
这里的“局部安全”不仅是最终后置正确。每个解引用前都要拥有相应 points-to 或权限,free 要拥有可释放资源,分配要取得 fresh 单元;因此一个线程不能先发生非法访问、再碰巧恢复正确终态。并行规则把这种逐步 fault avoidance 一并组合。
精确计数所用的有限 ghost 扩展
下面在顺序一致的交错语义中验证两个客户端各进入一次互斥临界区。共享地址 resource r in C 创建局部同步资源,执行 join 后这样回收。
为记录每次贡献,引入与真实地址命名空间分离的有限 ghost 堆。其单元片段记为
而
拆分与一致性直接来自上述部分组合运算。full 更新保持任意兼容 frame:总份额已是一,frame 不可能再含该名字的正份额,所以更新不会改变别人已拥有的断言。新鲜分配同样不与 frame 冲突。ghost 分配与更新只记录证明信息,不决定可执行程序的分支、真实写值或调度行为;擦除它们不改变具体执行。
分配两个不同的新名字
锁保管每个贡献的一半,客户端保管另一半。
这里
直觉
传统并发证明盯着每个外来动作问“它会不会改坏我的断言”。并发分离逻辑先问“它是否拥有进入这块状态的门票”。独占资源只能出现在一个线程的断言中;没有门票的代码不能合法读写它,因此局部链表更新可与另一线程的独立树更新直接并行,而不用比较每对指令。
所有权是逻辑资源,不等同于机器地址只被一个变量引用。两个指针可以都保存同一地址,但若当前线程没有相应权限,仍不能解引用。相反,权限代数可以把同一位置的只读份额分给多个线程。关键不是指针数量,而是证明状态中资源怎样拆分、转移和重组。
纯变量也会造成干扰。即使堆片段分离,线程 1 的后置若依赖普通变量 z,线程 2 又能赋值 z,单靠星号不能保护该事实;经典规则的自由变量与修改集合侧条件正用于堵住这条缝。把所有共享状态都画成“堆”而省略 store 部分,会漏掉这一层。
贡献凭证不直接拥有计数器
例子与边界
不相交单元与弱共享摘要
初始堆满足
两个线程分别执行 [p]:=[p]+1 与 [q]:=[q]+1。局部规格为
并行规则合成
无论哪次写先发生,另一格都在独立资源片段中。若
共享写入可以通过锁资源逐步解释。设锁的不变式为
这个存在量词不变式只足以证明安全访问,不足以独自证明“两个线程结束后值恰好增加二”。后一个结论还要在规格中追踪初值和每次更新的贡献;不能把很弱的资源摘要误当成精确功能规格。
一个客户端的完整局部推导
下面使用前述精确贡献不变式
Ci = with r when true do
ui := [x]
[x] := ui + 1
ghost gamma_i := 1
真实程序擦除最后一行。打开锁时,
读操作得到
通过资源不变式的开闭规则得到
并行组合、回收不变式与精确的二
从
两次局部推导由并行规则合成
并行命令结束意味着两个客户端都结束;再退出容纳所有使用者的局部资源作用域,按规则归还
打开这个最终存在量词时,两份
忽略证明用 ghost 堆,投影回真实程序就得到所需的部分正确性规格:从
两种临界区先后次序可以逐行核对;表只记录每次临界区已经关闭的时刻:
| 顺序 | 初始 |
第一次关闭后 | 第二次关闭后 |
|---|---|---|---|
等待、取得和释放可以有更多交错;互斥保证两段实际更新仍落在上述一种次序。证明已对任意
凭证防止哪些错误推导
第二次调用同一客户端增量规格需要
不能把
这份证明只依赖已列出的有限资源规则、互斥临界区语义与局部作用域回收;不是对任意现代 CSL 的完整可靠性证明。一般持久不变式的消除可能需要另外的取消凭证,不能套用这里的局部资源规则。
两个线程只读同一格时,完全不交的堆模型又过于严格,需要 分数权限 或其他共享只读代数。经典 CSL 也不自动建模弱内存重排、无锁算法的原子 ghost 更新、hazard pointer 或 epoch reclamation;直接套用堆不交规则会遗漏时间和内存回收协议。
推论与应用
并发分离逻辑使库规格保持“小脚印”:函数只声明实际触及的资源,调用者的其余堆可由 frame 原则保留,并行规则再把不同线程的小脚印拼接。资源不变式支持锁与临界区,所有权转移支持消息和线程创建,现代逻辑还加入 ghost state、原子更新与协议状态机来证明线性一致性。
安全性边界必须保持清楚。一个线程先拿锁
在弱内存模型中,即使权限排除了同址竞争,不同位置的写入仍可能以另一顺序被观察。若证明依赖 release/acquire 建立 happens-before,就要把原子模式和内存序纳入逻辑规则;经典顺序一致交错语义下的 CSL 证明不能自动承担这项硬件保证。
参考资料
[1] Peter W. O’Hearn, “Resources, Concurrency and Local Reasoning,” Theoretical Computer Science 375(1–3), 2007, pp. 271–307。
[2] Stephen Brookes, “A Semantics for Concurrent Separation Logic”, Theoretical Computer Science 375(1–3), 2007, pp. 227–270,资源上下文、临界区规则与并行组合的可靠性。
[3] John C. Reynolds, “Separation Logic: A Logic for Shared Mutable Data Structures,” LICS, 2002, pp. 55–74。
[4] Peter W. O’Hearn, “Separation Logic,” Communications of the ACM 62(2), 2019, pp. 86–95。
[5] Tej Chajed, Verifying a concurrent, crash-safe file system with sequential reasoning, MIT博士论文,2022,§3.1.2,pp. 31–33:ghost状态擦除、分数分配、拆分、一致性与full更新。
[6] Iris项目,ghost_var 正式库,ghost_var_agree、ghost_var_split、ghost_var_update与ghost_var_update_halves。这些引理支持分数ghost规则,不是本文局部锁算例已经机器验证的声明。