Rust in Everything
基于 parking_lot 0.12.5

RwLock

parking_lot::RwLock<T> 是 lock_api::RwLock<RawRwLock, T>(rwlock.rs:88)。原始锁 raw_rwlock.rs 1158 行,是 parking_lot 里最长的一个文件;它和 RawMutex 用的是同一个停车场、同一套「抢 → 没人停车才自旋 → 置位 → 在桶锁里验证后停车」的骨架,复杂度来自三种锁(读、写、可升级读)和「写者要等读者走光」这第二个等待条件。

flowchart TB
  subgraph st["state: AtomicUsize"]
    bits["读者数 | WRITER | UPGRADABLE | WRITER_PARKED | PARKED"]
  end
  rd["read / read_recursive"] -->|"WRITER_BIT 置位就排队"| q1["主队列 key = addr"]
  wr["write:第一步抢 WRITER_BIT"] -->|"抢不到"| q1
  wr -->|"第二步:还有读者"| q2["第二队列 key = addr + 1"]
  up["upgradable_read"] -->|"WRITER 或 UPGRADABLE 置位"| q1
  last["最后一个读者 unlock_shared"] -->|"unpark_one"| q2
  wun["写者 / 可升级读者解锁、降级、超时回滚"] -->|"wake_parked_threads:unpark_filter"| q1
  st --- q1

四章:

  1. 状态字与两条队列:文件头的设计说明(基于 Boost upgrade_mutex、两条队列、task-fair);五个位与读者计数;WRITER_BIT 在有读者时表示「写者在等」;三种 ParkToken 的值就是入场后状态字的增量;读者计数溢出;hardware-lock-elision。
  2. 读、写与写者优先:lock_common 骨架;写锁两步(抢 WRITER_BIT → wait_for_readers);读者看见 WRITER_BIT 就排队;写者解锁用 unpark_filter 叫醒一批读者或一个写者;超时回滚;read_recursive 与同线程重复读死锁(E5)。
  3. 可升级读、降级与 with_upgraded:可升级读的互斥规则;upgrade 一步换位;三种降级各叫醒谁;lock_api 的五个相关 trait;with_upgraded;自锁的几种写法(实测)。
  4. 和 std RwLock 比:std 在 macOS 上是 queue.rs、Linux 上是 futex;大小;吞吐引用 crossbeam 卷;读者流不断时写者的等待时间(E4,含 0.13.0 与 read_recursive 反向验证)。

和 RawMutex 的异同

RawMutexRawRwLock
状态AtomicU8,2 位AtomicUsize,4 位标志 + 读者数
停车 keyaddraddr(主队列)、addr + 1(等读者的写者)
解锁时叫醒unpark_one写者 / 可升级读者:unpark_filter;最后一个读者:unpark_one(addr + 1)
ParkToken不用(默认值)读 / 写 / 可升级三种,值即状态增量
公平交接TOKEN_HANDOFF同上,被叫醒的一批线程醒来即持有
自旋条件没有 PARKED_BIT没有 PARKED_BIT 也没有 WRITER_PARKED_BIT
同线程再加锁卡死写锁卡死;读锁在有写者等待时卡死(read_recursive 除外)

本部分的实验

#目录看什么章
E4exp-parking_lot/rwlock-writer/、v013-rwlock-writer/11 个读者持续读时,每 1 ms 一次的写锁要等多久;read_recursive 反向验证;std 与 0.13.0 列和 std RwLock 比
E5exp-parking_lot/recursive-read/同线程读 → 有写者排队 → 再读:read() 与 std 死锁,read_recursive() 与无写者时正常读、写与写者优先
—exp-parking_lot/pitfalls-upgradable/可升级读的互斥与几种自锁写法(功能实验)可升级读、降级与 with_upgraded

吞吐不重测,引用 crossbeam 卷 ShardedLock 页的 12 线程读写比例扫描。

本部分只写 0.12.5。0.13 删掉了 read_recursive 和 lock_api 的 RawRwLockRecursive* 两个 trait,改为单独的 RecursiveRwLock 类型,也删掉了 hardware-lock-elision,见 0.13 的变化。

💬 关联讨论

发起讨论
加载中...