Rust in Everything
基于 loom 0.7.2

能力边界

前面各章在遇到 loom 与真实语义不一致的地方都标了方向。这一部分把它们放在一起。两个方向的含义:

  • 假阳性:loom 报错,代码在真实环境里没问题。代价是误报和绕路,不会让错误溜过去。
  • 假阴性:代码在真实环境里有问题,loom 通过。代价是「通过」的含义变窄,要靠别的手段补。
flowchart LR
  subgraph fp["假阳性:loom 报错、代码没问题"]
    a1["SeqCst 访问当 AcqRel"]
    a2["wait_timeout 不超时"]
    a3["子线程 panic 穿出模型"]
    a4["RwLock 同线程嵌套读"]
    a5["mpsc 断开被报成死锁 / 泄漏"]
  end
  subgraph fn["假阴性:代码有问题、loom 通过"]
    b1["不做 load buffering"]
    b2["每个原子只留 7 次写"]
    b3["CAS weak 不伪失败"]
    b4["Condvar / park 不虚假唤醒"]
    b5["RwLock 没有写者优先"]
  end
  subgraph out["看不见"]
    c1["std 类型、系统调用、FFI、没走切换层的依赖"]
  end

总表

限制方向出处本卷实验怎么绕
SeqCst 访问当作 AcqRel假阳性rt/thread.rs:336-341;README「Unsupported features」E5:SB 全 SeqCst 访问仍给出 (0,0),30 个交错;改成 fence(SeqCst) 后消失改写成 Relaxed / Rel-Acq 访问 + fence(SeqCst)
不做 load buffering假阴性lib.rs:294-320;tests/litmus.rs 的 #[ignore]E5:LB 永远没有 (1,1);Relaxed RMW 版 SB 没有 (0,0)让正确性依赖 Acquire / Release,而不是「读不到将来的写」
每个原子只保留最近 7 次写假阴性MAX_ATOMIC_HISTORY = 7(rt/mod.rs:64-65)E6:写 9 次后只可能读到 3–9模型里同一原子的写不要超过 7 次
compare_exchange_weak 不伪失败假阴性sync/atomic/int.rs:94-104E16:单线程、无循环的 compare_exchange_weak 通过代码审查:_weak 必须在循环里
Condvar、park 不虚假唤醒假阴性rt/condvar.rs:39-60、rt/mod.rs:86-114E9:if 写法 8 个交错通过;换成 Notify 第 5 个交错被抓到在 loom 下把等待原语换成 Notify
wait_timeout 永不超时假阳性sync/condvar.rs:44-53E9:无人通知时报死锁超时分支不放进模型
lazy_static! 一轮内可能初始化两次、每轮 drop与真实行为不同lazy_static.rs:43-67E13:初始化里有 yield_now 时执行 2 次,去掉后 1 次初始化函数不要有依赖「只执行一次」的副作用
RwLock 没有写者优先假阴性rt/rwlock.rs:56-79写者等待时新读者照样进(9 个交错里 3 个)写者饥饿、嵌套读死锁要另找手段
RwLock 同线程嵌套读报内部错误假阳性rt/rwlock.rs:103-106E14:「invalid internal loom state」后 abort;不嵌套 9 个交错通过模型里改成不嵌套
子线程 panic 穿出模型,join 恒 Ok假阳性thread.rs:163-170E15:模型以子线程 panic 失败;std 下 join 返回 Err子线程里自己 catch_unwind
mpsc 发送方断开后 recv 报死锁、接收方 drop 后 send 报泄漏假阳性rt/mpsc.rs:103-133第 1 个交错报「deadlock」/「Messages leaked.」;std 返回 Err显式发结束消息
最多 5 个线程(含主线程)限制rt/mod.rs:61-62E12:spawn 5 个触发断言主线程承担一个角色
没有 compiler_fence可能假阴性sync/atomic/mod.rs:25-28 只导出 fence—crossbeam 用 fence 代替(更强)
Barrier、recv_timeout 是桩;没有 OnceLock、thread::scope、Weak不可用sync/barrier.rs、sync/mpsc.rs:63-70调用即「not implemented: … is not supported yet in Loom.」不放进模型,或在切换层里 mock
侵入式:只看得到 loom 类型看不见lib.rs:253-269E8:forget(std::sync::Arc) 通过切换层覆盖到要测的代码;其余靠压测、Miri、TSan

两章

  1. SeqCst 与 load buffering:E5 的四种 SB、LB、CoRR 并排对照 C11;seq_cst() 为什么是空函数、历史上两次提交各改了什么;loom 为什么给不出 LB 的 (1,1);同一原因下 Relaxed RMW 版 SB 也没有 (0,0)。
  2. 「loom 通过」意味着什么:一次通过覆盖的是四层边界的交集(可见的操作、模型形状、探索边界、内存模型),每层的出处与实测,以及和压力测试、Miri、TSan 怎么分工。

各条限制在哪一章首次出现:内存模型的几条在 03 内存模型,检测器相关的在 04 检测器,原语语义的在 05 同步原语的模型,运行参数相关的在 06 用法与调试。按「报错原文 → 怎么改」组织的版本见 09 常见坑。

💬 关联讨论

发起讨论
加载中...