1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
# spin-rs
[](https://crates.io/crates/spin)
[](https://docs.rs/spin/)
[](https://travis-ci.org/mvdnes/spin-rs)
Spin-based synchronization primitives.
This crate provides [spin-based](https://en.wikipedia.org/wiki/Spinlock)
versions of the primitives in `std::sync`. Because synchronization is done
through spinning, the primitives are suitable for use in `no_std` environments.
Before deciding to use `spin`, we recommend reading
[this superb blog post](https://matklad.github.io/2020/01/02/spinlocks-considered-harmful.html)
by [@matklad](https://github.com/matklad/) that discusses the pros and cons of
spinlocks. If you have access to `std`, it's likely that the primitives in
`std::sync` will serve you better except in very specific circumstances.
## Features
- `Mutex`, `RwLock`, `Once`, `Lazy` and `Barrier` equivalents
- Support for `no_std` environments
- [`lock_api`](https://crates.io/crates/lock_api) compatibility
- Upgradeable `RwLock` guards
- Guards can be sent and shared between threads
- Guard leaking
- Ticket locks
- Different strategies for dealing with contention
## Usage
Include the following under the `[dependencies]` section in your `Cargo.toml` file.
```toml
spin = "x.y"
```
## Example
When calling `lock` on a `Mutex` you will get a guard value that provides access
to the data. When this guard is dropped, the mutex will become available again.
```rust
extern crate spin;
use std::{sync::Arc, thread};
fn main() {
let counter = Arc::new(spin::Mutex::new(0));
let thread = thread::spawn({
let counter = counter.clone();
move || {
for _ in 0..100 {
*counter.lock() += 1;
}
}
});
for _ in 0..100 {
*counter.lock() += 1;
}
thread.join().unwrap();
assert_eq!(*counter.lock(), 200);
}
```
## Feature flags
The crate comes with a few feature flags that you may wish to use.
- `mutex` enables the `Mutex` type.
- `spin_mutex` enables the `SpinMutex` type.
- `ticket_mutex` enables the `TicketMutex` type.
- `use_ticket_mutex` switches to a ticket lock for the implementation of `Mutex`. This
is recommended only on targets for which ordinary spinning locks perform very badly
because it will change the implementation used by other crates that depend on `spin`.
- `rwlock` enables the `RwLock` type.
- `once` enables the `Once` type.
- `lazy` enables the `Lazy` type.
- `barrier` enables the `Barrier` type.
- `lock_api` enables support for [`lock_api`](https://crates.io/crates/lock_api)
- `std` enables support for thread yielding instead of spinning.
- `portable_atomic` enables usage of the `portable-atomic` crate
to support platforms without native atomic operations (Cortex-M0, etc.).
The `portable_atomic_unsafe_assume_single_core` cfg or `critical-section` feature
of `portable-atomic` crate must also be set by the final binary crate.
When using the cfg, this can be done by adapting the following snippet to the `.cargo/config` file:
```
[target.<target>]
rustflags = [ "--cfg", "portable_atomic_unsafe_assume_single_core" ]
```
Note that this cfg is unsafe by nature, and enabling it for multicore systems is unsound.
When using the `critical-section` feature, you need to implement the critical-section
implementation that sound for your system by implementing an unsafe trait.
See [the documentation for the `portable-atomic` crate](https://docs.rs/portable-atomic/latest/portable_atomic/#optional-cfg)
for more information.
## Remarks
It is often desirable to have a lock shared between threads. Wrapping the lock in an
`std::sync::Arc` is route through which this might be achieved.
Locks provide zero-overhead access to their data when accessed through a mutable
reference by using their `get_mut` methods.
The behaviour of these lock is similar to their namesakes in `std::sync`. they
differ on the following:
- Locks will not be poisoned in case of failure.
- Threads will not yield to the OS scheduler when encounter a lock that cannot be
accessed. Instead, they will 'spin' in a busy loop until the lock becomes available.
Many of the feature flags listed above are enabled by default. If you're writing a
library, we recommend disabling those that you don't use to avoid increasing compilation
time for your crate's users. You can do this like so:
```
[dependencies]
spin = { version = "x.y", default-features = false, features = [...] }
```
## Minimum Safe Rust Version (MSRV)
This crate is guaranteed to compile on a Minimum Safe Rust Version (MSRV) of 1.38.0 and above.
This version will not be changed without a minor version bump.
## License
`spin` is distributed under the MIT License, (See `LICENSE`).
|