Rust in Everything
基于 parking_lot 0.12.5

Mutex 家族

parking_lot 的三种互斥锁共用一个原始锁:RawMutex,一个 AtomicU8 里的两位。Mutex<T>、FairMutex<T>、ReentrantMutex<T> 都是 lock_api 泛型外壳的类型别名,parking_lot 这一层只写「原始锁怎么加、怎么解」,守卫体系全在 lock_api(06 lock_api)。

flowchart TB
  m["Mutex&lt;T&gt; = lock_api::Mutex&lt;RawMutex, T&gt;"] --> rm["RawMutex:AtomicU8,LOCKED_BIT / PARKED_BIT"]
  fm["FairMutex&lt;T&gt; = lock_api::Mutex&lt;RawFairMutex, T&gt;"] --> rfm["RawFairMutex(RawMutex):unlock 换成 unlock_fair"] --> rm
  re["ReentrantMutex&lt;T&gt; = lock_api::ReentrantMutex&lt;RawMutex, RawThreadId, T&gt;"] --> rrm["RawReentrantMutex:owner + lock_count"] --> rm
  rm -->|"lock_slow:park(addr)"| core["parking_lot_core 停车场"]
  rm -->|"unlock_slow:unpark_one(addr, 回调)"| core
  cv["Condvar"] -.->|"requeue 时直接改 PARKED_BIT"| rm

四章:

  1. RawMutex 的一字节状态机:四种状态与「锁被持有时 PARKED_BIT 只在桶锁里清」的不变量;快路径各一次 CAS;lock_slow 的抢、转、置位、停车;unlock_slow 在桶锁里的回调怎样决定交接(TOKEN_HANDOFF)还是放开;给 Condvar 用的 mark_parked_if_locked;没有毒化。
  2. 公平解锁、bump 与 FairMutex:unlock_fair 与 unlock 只差一个参数;bump 有人等才让;FairMutex 只换了 unlock;最终公平的兜底效果与公平的代价(E3)。
  3. ReentrantMutex:lock_api 的 owner + lock_count,parking_lot 用线程局部变量的地址当线程 id;守卫只给 &T、恒为 !Send。
  4. 和 std Mutex 比:std 在 Linux 上是 futex、在 macOS 上是懒分配的 pthread mutex;大小表(E1);本机 0.12.5 / std / 0.13.0 三列吞吐与尾延迟(E2)。

一次有竞争的加锁在两侧(锁和停车场)怎么交替,全景时序图在 一次有竞争的加锁;停车场一侧的 park / unpark_one 在 park 与四种 unpark。

三种锁对照

MutexFairMutexReentrantMutex
原始锁RawMutexRawFairMutex(RawMutex)RawReentrantMutex<RawMutex, RawThreadId>
本机 size_of::<_<()>>()1124
普通解锁插队允许,桶计时器 0–1 ms 兜底一次交接有人停车就交接计数归零时同 Mutex
同线程再加锁卡死卡死计数加一
守卫给出&mut T&mut T只有 &T
守卫 Send看 send_guard feature看 send_guard feature永不
能配 Condvar能不能(守卫类型不同)不能
毒化无无无

本部分的实验

#目录看什么章
E1exp-parking_lot/sizes/本机 size_of 表;Linux 两个目标上 std 的大小用编译期断言核实和 std Mutex 比
E2exp-parking_lot/mutex-throughput/、v013-mutex-throughput/0.12.5 / std / 0.13.0 的 ns/op 与单次 lock() 的 p50 / p99 / p99.9和 std Mutex 比
E3exp-parking_lot/eventual-fairness/、v013-eventual-fairness/最长连续独占次数;持锁 1 µs 到 10 ms 五档;unlock_fair / FairMutex 的代价公平解锁、bump 与 FairMutex

计时类 crate 都去掉了 base 模板里的 deadlock_detection feature:开着它,每次加解锁都多一次线程局部记账(死锁检测)。

💬 关联讨论

发起讨论
加载中...