Rust in Everything
基于 parking_lot 0.12.5

动手

前面十章读的是 parking_lot 怎么做。这一部分反过来,用最少的代码把三层各写一遍,再确认删掉或挪动某一行会错。页面只放思路和关键片段,完整工程在 exp-parking_lot/hands-on/:

  • src/lot.rs:最小停车场;src/mini_mutex.rs:建在它上面的 1 字节 mutex;
  • src/sema.rs:直接用 parking_lot_core 的计数信号量;
  • src/spin.rs:lock_api 外壳下的 TTAS 自旋锁,实现了 RawMutexTimed;
  • tests/hands_on.rs:8 个测试;src/bin/lost_wakeup.rs、src/bin/bench.rs:压测与计时。

依赖 parking_lot =0.12.5、parking_lot_core =0.9.12、lock_api =0.4.14,不开 deadlock_detection。本机 M2 Max(8 性能核 + 4 能效核),macOS,rustc 1.99.1,--offline --release。

  1. 最小停车场与 1 字节 mutex:64 个桶,每桶一把 std Mutex 护着一个 FIFO;park 在桶锁里跑 validate,unpark_one 在桶锁里跑回调。mutex 32 线程计数精确;吞吐和 parking_lot 同量级。把 validate 挪到桶锁外,10 次压测 10 次卡死。
  2. 用 parking_lot_core 写计数信号量:一个 AtomicUsize,最低位表示「有人在等」,其余是许可数;规则和 RawMutex 一样,等待位只在桶锁里清。压测 3 组同时持有数从不超过许可数;反向:「先看再减」的写法 8 个线程同时拿到 1 个许可。
  3. lock_api 自旋锁加 RawMutexTimed:test-and-test-and-set,再补 try_lock_for / try_lock_until;超时测试误差在微秒级;反向:只试一次就放弃的实现两个测试失败。
flowchart TB
  lot["最小停车场:64 桶 + FIFO"] --> mm["1 字节 mutex:LOCKED / PARKED"]
  mm --> rev1["反向:validate 移到桶锁外,10/10 卡死"]
  core["parking_lot_core:park / unpark_one"] --> sem["计数信号量:WAITERS 位 + 许可数"]
  sem --> rev2["反向:先看再减,同时持有 8 > 1"]
  api["lock_api:RawMutex + RawMutexTimed"] --> spin["TTAS 自旋锁 + 超时"]
  spin --> rev3["反向:只试一次,超时测试失败"]
  lot -.->|"同一个协议"| core
  mm -.->|"同一个外壳"| api

怎么跑

cd exp-parking_lot/hands-on
cargo test --offline --release                                   # 8 个测试
cargo run --offline --release --bin lost_wakeup -- 4 200000 10 5 # 正确版本:0/10 卡死
cargo run --offline --release --bin bench -- mini 12 1000000 0  # mini / pl / std
# 反向验证,各用一个 feature,建议各给一个 --target-dir 免得来回重编
cargo run --offline --release --features validate_outside --bin lost_wakeup -- 4 200000 10 5
cargo test --offline --release --features broken_sema
cargo test --offline --release --features broken_timed

所有多线程测试都在看门狗下跑:超时就以「hang: watchdog fired」失败,不会挂住测试进程;lost_wakeup 卡住的那一轮记为 HANG,最后以退出码 3 结束。

和课程的关系

三个实现刻意省掉了很多:停车场没有超时、没有 unpark_all / unpark_requeue、桶数固定、不处理线程局部变量已析构的情况;mutex 没有公平交接;信号量没有超时、release 不检查溢出;自旋锁没有退避和让出。每一页末尾列出了省掉的部分和 parking_lot 对应的做法。本卷只保证骨架是对的,并且能说出「桶锁里验证」「等待位只在桶锁里清」「unsafe impl 担保了什么」各防的是什么。

loom 帮不上忙:parking_lot_core 用的是真实的原子和系统调用,不能在 loom 的模型里运行。所以这里的正确性证据只有两类:大量线程的压力测试加计数断言,以及「故意写错一处,测试必须失败」的反向验证。这能说明测法有效,不能证明没有更罕见的交错。

💬 关联讨论

发起讨论
加载中...