55 个版本

0.12.3 2024 年 5 月 24 日
0.12.1 2022 年 5 月 31 日
0.12.0 2022 年 1 月 28 日
0.11.2 2021 年 8 月 27 日
0.2.7 2016 年 7 月 28 日

#1 in 并发

Download history 2542979/week @ 2024-05-02 2508951/week @ 2024-05-09 2628620/week @ 2024-05-16 2551273/week @ 2024-05-23 2746084/week @ 2024-05-30 2672160/week @ 2024-06-06 2880841/week @ 2024-06-13 2724734/week @ 2024-06-20 2604069/week @ 2024-06-27 2455375/week @ 2024-07-04 2750099/week @ 2024-07-11 2762166/week @ 2024-07-18 2758854/week @ 2024-07-25 2911444/week @ 2024-08-01 3241281/week @ 2024-08-08 3030336/week @ 2024-08-15

12,486,159 每月下载量
用于 29,337 个 Crates(2,676 个直接使用)

MIT/Apache

420KB
8K SLoC

parking_lot

Rust Crates.io

文档(同步原语)

文档(核心停车场 API)

文档(类型安全锁 API)

此库提供了比 Rust 标准库中的更小、更快、更灵活的 MutexRwLockCondvarOnce 实现,以及支持递归加锁的 ReentrantMutex 类型。它还公开了一个低级 API,用于创建自己的高效同步原语。

在 x86_64 Linux 上进行测试时,发现当无竞争时,parking_lot::Mutex 比标准库中的 std::sync::Mutex 快 1.5 倍,而在多个线程竞争时则快 5 倍。对于 RwLock 的数值取决于读者和写线程的数量,但几乎总是比标准库中的 RwLock 快,在某些情况下甚至快 50 倍。

特性

此库提供的原语与 Rust 标准库中的原语相比具有几个优势

  1. MutexOnce 仅需 1 字节存储空间,而 CondvarRwLock 仅需 1 个字节的存储空间。另一方面,在某些平台(如 macOS 和其他一些平台)上,标准库原语需要动态分配的 Box 来持有特定于操作系统的同步原语。特别是 Mutex 的小尺寸特别鼓励使用细粒度锁来提高并行性。
  2. 无竞争锁的获取和释放通过快速的内联路径完成,这些路径仅需要一次原子操作。
  3. 微竞争(具有短关键区的竞争锁)通过在尝试获取锁时旋转几次来有效地处理。
  4. 锁是自适应的,在几次自旋尝试失败后,会挂起一个线程。这使得锁适用于长和短的关键部分。
  5. CondvarRwLockOnce 在 Windows XP 上运行,与那些类型的标准库版本不同。
  6. RwLock 利用支持该功能的处理器的硬件锁消除,这可以在许多读者的情况下带来巨大的性能提升。这必须通过 hardware-lock-elision 功能来启用。
  7. RwLock 使用任务公平锁策略,这避免了读者和写者的饥饿,而标准库版本则没有任何保证。
  8. Condvar 保证不会产生虚假唤醒。只有在超时或被通知唤醒时,线程才会被唤醒。
  9. Condvar::notify_all 只会唤醒一个线程,并将其余的线程重新排队等待相关的 Mutex。这避免了所有线程同时尝试获取锁的雷鸣 herd 问题。
  10. RwLock 支持将写锁原子降级为读锁。
  11. MutexRwLock 允许不带 RAII 守护对象进行原始解锁。
  12. Mutex<()>RwLock<()> 允许不带 RAII 守护对象进行原始锁定。
  13. MutexRwLock 支持最终公平性,这允许它们在平均情况下公平,而不牺牲性能。
  14. 支持递归锁定的 ReentrantMutex 类型。
  15. 一个实验性的死锁检测器,适用于 MutexRwLockReentrantMutex。默认情况下,此功能是禁用的,可以通过 deadlock_detection 功能启用。
  16. RwLock 支持将“可升级”的读锁原子升级为写锁。
  17. 可选支持 serde。通过 serde 功能启用。注意!此支持仅适用于 MutexReentrantMutexRwLockCondvarOnce 目前不支持。
  18. 当启用 send_guard 功能时,锁守护者可以发送到其他线程。

停车场

为了保持这些原语的大小,所有的线程排队和挂起功能都卸载到 停车场。这个想法基于 Webkit WTF::ParkingLot 类,该类本质上是一个哈希表映射,将锁地址映射到挂起的(休眠的)线程队列。Webkit 停车场本身受到了 Linux futexes 的启发,但它更强大,因为它允许在持有队列锁的同时调用回调。

夜间版与稳定版

在稳定版 Rust 上使用此库时有一些限制。

  • wasm32-unknown-unknown 目标仅在夜间构建版本中完全支持,需要在 RUSTFLAGS 中添加 -C target-feature=+atomics,并通过传递给 cargo 的 -Zbuild-std=panic_abort,std 实现。在稳定版本中,parking_lot 将大致正常工作,唯一的区别是如果遇到死锁,它将触发 panic 而不是无限期地阻塞。只需确保不要在稳定版本上启用 -C target-feature=+atomics,因为这将允许 wasm 在多线程中运行,这将完全破坏 parking_lot 的并发保证。

要启用仅夜间构建的功能,您需要启用 Cargo 中的 nightly 功能(见下文)。

使用方法

将以下内容添加到您的 Cargo.toml

[dependencies]
parking_lot = "0.12"

要启用仅夜间构建的功能,将以下内容添加到您的 Cargo.toml

[dependencies]
parking_lot = { version = "0.12", features = ["nightly"] }

可以通过启用 deadlock_detection Cargo 功能来启用实验性的死锁检测器。

要允许将 MutexGuardRwLock*Guard 发送到其他线程,请启用 send_guard 选项。

请注意,deadlock_detectionsend_guard 功能不兼容,不能同时使用。

可以通过启用 hardware-lock-elision 功能来启用对 x86 的硬件锁消除支持。由于使用了内联汇编,这需要 Rust 1.59。

核心 parking_lot API 由 parking_lot_core crate 提供。它独立于 parking_lot crate 中的同步原语,以便核心 API 的更改不会对 parking_lot 的用户造成破坏性更改。

最低 Rust 版本

当前所需的最低 Rust 版本是 1.56。任何对此的更改都视为破坏性更改,并将需要主要版本号的升级。

许可

以下任一许可下提供

任选其一。

贡献

除非您明确声明,否则任何有意提交以包含在您的工作中的贡献,根据 Apache-2.0 许可证的定义,应按照上述方式双许可,不附加任何其他条款或条件。

依赖项

~0–6MB
~22K SLoC