动手
前面十章读的是 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 字节 mutex:64 个桶,每桶一把 std
Mutex护着一个 FIFO;park在桶锁里跑validate,unpark_one在桶锁里跑回调。mutex 32 线程计数精确;吞吐和 parking_lot 同量级。把validate挪到桶锁外,10 次压测 10 次卡死。 - 用 parking_lot_core 写计数信号量:一个
AtomicUsize,最低位表示「有人在等」,其余是许可数;规则和RawMutex一样,等待位只在桶锁里清。压测 3 组同时持有数从不超过许可数;反向:「先看再减」的写法 8 个线程同时拿到 1 个许可。 - 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 的模型里运行。所以这里的正确性证据只有两类:大量线程的压力测试加计数断言,以及「故意写错一处,测试必须失败」的反向验证。这能说明测法有效,不能证明没有更罕见的交错。
💬 关联讨论
发起讨论加载中...