spin-rs
Spin-based synchronization primitives.
This crate provides spin-based
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
by @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,LazyandBarrierequivalents- Support for
no_stdenvironments lock_apicompatibility- Upgradeable
RwLockguards - 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.
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.
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.
-
mutexenables theMutextype. -
spin_mutexenables theSpinMutextype. -
ticket_mutexenables theTicketMutextype. -
use_ticket_mutexswitches to a ticket lock for the implementation ofMutex. 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 onspin. -
rwlockenables theRwLocktype. -
onceenables theOncetype. -
lazyenables theLazytype. -
barrierenables theBarriertype. -
lock_apienables support forlock_api -
stdenables support for thread yielding instead of spinning. -
portable_atomicenables usage of theportable-atomiccrate to support platforms without native atomic operations (Cortex-M0, etc.). Theportable_atomic_unsafe_assume_single_corecfg flag must also be set by the final binary crate. This can be done by adapting the following snippet to the.cargo/configfile:[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.
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 = [...] }
License
spin is distributed under the MIT License, (See LICENSE).