2016-05-11 18:26:54 +00:00
|
|
|
parking_lot
|
|
|
|
============
|
|
|
|
|
2022-02-21 05:14:15 +00:00
|
|
|
[![Rust](https://github.com/Amanieu/parking_lot/workflows/Rust/badge.svg)](https://github.com/Amanieu/parking_lot/actions)
|
2020-05-10 14:43:41 +00:00
|
|
|
[![Crates.io](https://img.shields.io/crates/v/parking_lot.svg)](https://crates.io/crates/parking_lot)
|
2016-05-11 18:26:54 +00:00
|
|
|
|
2018-06-08 00:02:59 +00:00
|
|
|
[Documentation (synchronization primitives)](https://docs.rs/parking_lot/)
|
2016-08-24 22:21:46 +00:00
|
|
|
|
2018-06-08 00:02:59 +00:00
|
|
|
[Documentation (core parking lot API)](https://docs.rs/parking_lot_core/)
|
|
|
|
|
|
|
|
[Documentation (type-safe lock API)](https://docs.rs/lock_api/)
|
2016-05-11 18:26:54 +00:00
|
|
|
|
|
|
|
This library provides implementations of `Mutex`, `RwLock`, `Condvar` and
|
|
|
|
`Once` that are smaller, faster and more flexible than those in the Rust
|
2017-02-02 13:21:17 +00:00
|
|
|
standard library, as well as a `ReentrantMutex` type which supports recursive
|
|
|
|
locking. It also exposes a low-level API for creating your own efficient
|
|
|
|
synchronization primitives.
|
2016-05-11 18:26:54 +00:00
|
|
|
|
2016-05-23 07:50:26 +00:00
|
|
|
When tested on x86_64 Linux, `parking_lot::Mutex` was found to be 1.5x
|
2016-05-27 14:31:32 +00:00
|
|
|
faster than `std::sync::Mutex` when uncontended, and up to 5x faster when
|
2016-05-23 07:50:26 +00:00
|
|
|
contended from multiple threads. The numbers for `RwLock` vary depending on
|
|
|
|
the number of reader and writer threads, but are almost always faster than
|
2016-05-27 14:31:32 +00:00
|
|
|
the standard library `RwLock`, and even up to 50x faster in some cases.
|
2016-05-23 07:50:26 +00:00
|
|
|
|
2016-05-11 18:26:54 +00:00
|
|
|
## Features
|
|
|
|
|
|
|
|
The primitives provided by this library have several advantages over those
|
|
|
|
in the Rust standard library:
|
|
|
|
|
2016-05-23 07:50:26 +00:00
|
|
|
1. `Mutex` and `Once` only require 1 byte of storage space, while `Condvar`
|
|
|
|
and `RwLock` only require 1 word of storage space. On the other hand the
|
2016-05-11 18:26:54 +00:00
|
|
|
standard library primitives require a dynamically allocated `Box` to hold
|
|
|
|
OS-specific synchronization primitives. The small size of `Mutex` in
|
|
|
|
particular encourages the use of fine-grained locks to increase
|
|
|
|
parallelism.
|
|
|
|
2. Since they consist of just a single atomic variable, have constant
|
|
|
|
initializers and don't need destructors, these primitives can be used as
|
2019-11-25 18:48:16 +00:00
|
|
|
`static` global variables. The standard library primitives require
|
2016-05-11 18:26:54 +00:00
|
|
|
dynamic initialization and thus need to be lazily initialized with
|
|
|
|
`lazy_static!`.
|
|
|
|
3. Uncontended lock acquisition and release is done through fast inline
|
|
|
|
paths which only require a single atomic operation.
|
|
|
|
4. Microcontention (a contended lock with a short critical section) is
|
|
|
|
efficiently handled by spinning a few times while trying to acquire a
|
|
|
|
lock.
|
|
|
|
5. The locks are adaptive and will suspend a thread after a few failed spin
|
|
|
|
attempts. This makes the locks suitable for both long and short critical
|
|
|
|
sections.
|
2016-05-27 14:31:32 +00:00
|
|
|
6. `Condvar`, `RwLock` and `Once` work on Windows XP, unlike the standard
|
|
|
|
library versions of those types.
|
2016-05-23 08:45:01 +00:00
|
|
|
7. `RwLock` takes advantage of hardware lock elision on processors that
|
|
|
|
support it, which can lead to huge performance wins with many readers.
|
2022-01-28 13:04:05 +00:00
|
|
|
This must be enabled with the `hardware-lock-elision` feature.
|
2017-11-14 11:48:26 +00:00
|
|
|
8. `RwLock` uses a task-fair locking policy, which avoids reader and writer
|
2016-08-26 03:25:41 +00:00
|
|
|
starvation, whereas the standard library version makes no guarantees.
|
2017-11-14 11:48:26 +00:00
|
|
|
9. `Condvar` is guaranteed not to produce spurious wakeups. A thread will
|
2016-05-27 14:31:32 +00:00
|
|
|
only be woken up if it timed out or it was woken up by a notification.
|
2017-11-14 11:48:26 +00:00
|
|
|
10. `Condvar::notify_all` will only wake up a single thread and requeue the
|
2016-05-27 14:31:32 +00:00
|
|
|
rest to wait on the associated `Mutex`. This avoids a thundering herd
|
|
|
|
problem where all threads try to acquire the lock at the same time.
|
2017-11-14 11:48:26 +00:00
|
|
|
11. `RwLock` supports atomically downgrading a write lock into a read lock.
|
|
|
|
12. `Mutex` and `RwLock` allow raw unlocking without a RAII guard object.
|
|
|
|
13. `Mutex<()>` and `RwLock<()>` allow raw locking without a RAII guard
|
2016-08-15 20:20:44 +00:00
|
|
|
object.
|
2017-11-14 11:48:26 +00:00
|
|
|
14. `Mutex` and `RwLock` support [eventual fairness](https://trac.webkit.org/changeset/203350)
|
2016-08-26 09:28:28 +00:00
|
|
|
which allows them to be fair on average without sacrificing performance.
|
2017-11-14 11:48:26 +00:00
|
|
|
15. A `ReentrantMutex` type which supports recursive locking.
|
|
|
|
16. An *experimental* deadlock detector that works for `Mutex`,
|
2017-08-29 19:30:10 +00:00
|
|
|
`RwLock` and `ReentrantMutex`. This feature is disabled by default and
|
2017-11-14 11:48:26 +00:00
|
|
|
can be enabled via the `deadlock_detection` feature.
|
2017-11-27 18:18:38 +00:00
|
|
|
17. `RwLock` supports atomically upgrading an "upgradable" read lock into a
|
|
|
|
write lock.
|
2019-04-24 23:01:56 +00:00
|
|
|
18. Optional support for [serde](https://docs.serde.rs/serde/). Enable via the
|
2019-05-01 13:42:43 +00:00
|
|
|
feature `serde`. **NOTE!** this support is for `Mutex`, `ReentrantMutex`,
|
|
|
|
and `RwLock` only; `Condvar` and `Once` are not currently supported.
|
2020-05-30 13:11:55 +00:00
|
|
|
19. Lock guards can be sent to other threads when the `send_guard` feature is
|
2020-05-27 23:07:18 +00:00
|
|
|
enabled.
|
2016-05-11 18:26:54 +00:00
|
|
|
|
|
|
|
## The parking lot
|
|
|
|
|
|
|
|
To keep these primitives small, all thread queuing and suspending
|
|
|
|
functionality is offloaded to the *parking lot*. The idea behind this is
|
2017-04-02 16:18:32 +00:00
|
|
|
based on the Webkit [`WTF::ParkingLot`](https://webkit.org/blog/6161/locking-in-webkit/)
|
|
|
|
class, which essentially consists of a hash table mapping of lock addresses
|
|
|
|
to queues of parked (sleeping) threads. The Webkit parking lot was itself
|
2022-02-21 05:14:15 +00:00
|
|
|
inspired by Linux [futexes](https://man7.org/linux/man-pages/man2/futex.2.html),
|
2017-04-02 16:18:32 +00:00
|
|
|
but it is more powerful since it allows invoking callbacks while holding a queue
|
|
|
|
lock.
|
2016-05-11 18:26:54 +00:00
|
|
|
|
2016-05-17 14:39:12 +00:00
|
|
|
## Nightly vs stable
|
|
|
|
|
|
|
|
There are a few restrictions when using this library on stable Rust:
|
2016-05-11 18:26:54 +00:00
|
|
|
|
2022-02-19 05:16:31 +00:00
|
|
|
- The `wasm32-unknown-unknown` target is only fully supported on nightly with
|
2022-02-19 08:41:58 +00:00
|
|
|
`-C target-feature=+atomics` in `RUSTFLAGS` and `-Z build-std` passed to cargo.
|
|
|
|
parking_lot will work mostly fine on stable, the only difference is it will
|
2022-02-19 05:16:31 +00:00
|
|
|
panic instead of block forever if you hit a deadlock.
|
2022-02-19 08:41:58 +00:00
|
|
|
Just make sure not to enable `-C target-feature=+atomics` on stable as that
|
|
|
|
will allow wasm to run with multiple threads which will completely break
|
|
|
|
parking_lot's concurrency guarantees.
|
2016-05-17 14:39:12 +00:00
|
|
|
|
2017-12-29 16:38:25 +00:00
|
|
|
To enable nightly-only functionality, you need to enable the `nightly` feature
|
|
|
|
in Cargo (see below).
|
|
|
|
|
2016-05-17 14:39:12 +00:00
|
|
|
## Usage
|
2016-05-11 18:26:54 +00:00
|
|
|
|
|
|
|
Add this to your `Cargo.toml`:
|
|
|
|
|
|
|
|
```toml
|
|
|
|
[dependencies]
|
2022-02-21 05:14:15 +00:00
|
|
|
parking_lot = "0.12"
|
2016-05-11 18:26:54 +00:00
|
|
|
```
|
|
|
|
|
2016-05-17 14:39:12 +00:00
|
|
|
To enable nightly-only features, add this to your `Cargo.toml` instead:
|
|
|
|
|
|
|
|
```toml
|
|
|
|
[dependencies]
|
2022-02-21 05:14:15 +00:00
|
|
|
parking_lot = { version = "0.12", features = ["nightly"] }
|
2016-05-17 14:39:12 +00:00
|
|
|
```
|
|
|
|
|
2017-12-29 16:38:25 +00:00
|
|
|
The experimental deadlock detector can be enabled with the
|
|
|
|
`deadlock_detection` Cargo feature.
|
|
|
|
|
2020-05-27 23:07:18 +00:00
|
|
|
To allow sending `MutexGuard`s and `RwLock*Guard`s to other threads, enable the
|
|
|
|
`send_guard` option.
|
|
|
|
|
|
|
|
Note that the `deadlock_detection` and `send_guard` features are incompatible
|
|
|
|
and cannot be used together.
|
|
|
|
|
2022-01-28 13:04:05 +00:00
|
|
|
Hardware lock elision support for x86 can be enabled with the
|
|
|
|
`hardware-lock-elision` feature. This requires Rust 1.59 due to the use of
|
|
|
|
inline assembly.
|
|
|
|
|
2016-08-24 22:21:46 +00:00
|
|
|
The core parking lot API is provided by the `parking_lot_core` crate. It is
|
|
|
|
separate from the synchronization primitives in the `parking_lot` crate so that
|
|
|
|
changes to the core API do not cause breaking changes for users of `parking_lot`.
|
|
|
|
|
2018-08-29 15:43:01 +00:00
|
|
|
## Minimum Rust version
|
|
|
|
|
2022-01-28 13:06:24 +00:00
|
|
|
The current minimum required Rust version is 1.49. Any change to this is
|
2018-08-29 15:43:01 +00:00
|
|
|
considered a breaking change and will require a major version bump.
|
|
|
|
|
2016-05-11 18:26:54 +00:00
|
|
|
## License
|
|
|
|
|
|
|
|
Licensed under either of
|
|
|
|
|
2022-02-21 05:14:15 +00:00
|
|
|
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
|
|
|
|
* MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
|
2016-05-11 18:26:54 +00:00
|
|
|
|
|
|
|
at your option.
|
|
|
|
|
|
|
|
### Contribution
|
|
|
|
|
|
|
|
Unless you explicitly state otherwise, any contribution intentionally submitted
|
|
|
|
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
|
|
|
|
additional terms or conditions.
|