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
四章:
- 状态字与两条队列:文件头的设计说明(基于 Boost
upgrade_mutex、两条队列、task-fair);五个位与读者计数;WRITER_BIT在有读者时表示「写者在等」;三种ParkToken的值就是入场后状态字的增量;读者计数溢出;hardware-lock-elision。 - 读、写与写者优先:
lock_common骨架;写锁两步(抢WRITER_BIT→wait_for_readers);读者看见WRITER_BIT就排队;写者解锁用unpark_filter叫醒一批读者或一个写者;超时回滚;read_recursive与同线程重复读死锁(E5)。 - 可升级读、降级与 with_upgraded:可升级读的互斥规则;
upgrade一步换位;三种降级各叫醒谁;lock_api 的五个相关 trait;with_upgraded;自锁的几种写法(实测)。 - 和 std RwLock 比:std 在 macOS 上是
queue.rs、Linux 上是 futex;大小;吞吐引用 crossbeam 卷;读者流不断时写者的等待时间(E4,含 0.13.0 与read_recursive反向验证)。
和 RawMutex 的异同
RawMutex | RawRwLock | |
|---|---|---|
| 状态 | AtomicU8,2 位 | AtomicUsize,4 位标志 + 读者数 |
| 停车 key | addr | addr(主队列)、addr + 1(等读者的写者) |
| 解锁时叫醒 | unpark_one | 写者 / 可升级读者:unpark_filter;最后一个读者:unpark_one(addr + 1) |
ParkToken | 不用(默认值) | 读 / 写 / 可升级三种,值即状态增量 |
| 公平交接 | TOKEN_HANDOFF | 同上,被叫醒的一批线程醒来即持有 |
| 自旋条件 | 没有 PARKED_BIT | 没有 PARKED_BIT 也没有 WRITER_PARKED_BIT |
| 同线程再加锁 | 卡死 | 写锁卡死;读锁在有写者等待时卡死(read_recursive 除外) |
本部分的实验
| # | 目录 | 看什么 | 章 |
|---|---|---|---|
| E4 | exp-parking_lot/rwlock-writer/、v013-rwlock-writer/ | 11 个读者持续读时,每 1 ms 一次的写锁要等多久;read_recursive 反向验证;std 与 0.13.0 列 | 和 std RwLock 比 |
| E5 | exp-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 的变化。
💬 关联讨论
发起讨论加载中...