//! A light-weight lock guarded by an atomic boolean. //! //! Most efficient when contention is low, acquiring the lock is a single //! atomic swap, and releasing it just 1 more atomic swap. //! //! # Example //! //! ``` //! use std::sync::Arc; //! use try_lock::TryLock; //! //! // a thing we want to share //! struct Widget { //! name: String, //! } //! //! // lock it up! //! let widget1 = Arc::new(TryLock::new(Widget { //! name: "Spanner".into(), //! })); //! //! let widget2 = widget1.clone(); //! //! //! // mutate the widget //! let mut locked = widget1.try_lock().expect("example isn't locked yet"); //! locked.name.push_str(" Bundle"); //! //! // hands off, buddy //! let not_locked = widget2.try_lock(); //! assert!(not_locked.is_none(), "widget1 has the lock"); //! //! // ok, you can have it //! drop(locked); //! //! let locked2 = widget2.try_lock().expect("widget1 lock is released"); //! //! assert_eq!(locked2.name, "Spanner Bundle"); //! ```
#[cfg(test)] externcrate core;
use core::cell::UnsafeCell; use core::fmt; use core::ops::{Deref, DerefMut}; use core::sync::atomic::{AtomicBool, Ordering}; use core::marker::PhantomData;
/// A light-weight lock guarded by an atomic boolean. /// /// Most efficient when contention is low, acquiring the lock is a single /// atomic swap, and releasing it just 1 more atomic swap. /// /// It is only possible to try to acquire the lock, it is not possible to /// wait for the lock to become ready, like with a `Mutex`. #[derive(Default)] pubstruct TryLock<T> {
is_locked: AtomicBool,
value: UnsafeCell<T>,
}
impl<T> TryLock<T> { /// Create a `TryLock` around the value. #[inline] pubfn new(val: T) -> TryLock<T> {
TryLock {
is_locked: AtomicBool::new(false),
value: UnsafeCell::new(val),
}
}
/// Try to acquire the lock of this value. /// /// If the lock is already acquired by someone else, this returns /// `None`. You can try to acquire again whenever you want, perhaps /// by spinning a few times, or by using some other means of /// notification. /// /// # Note /// /// The default memory ordering is to use `Acquire` to lock, and `Release` /// to unlock. If different ordering is required, use /// [`try_lock_explicit`](TryLock::try_lock_explicit) or /// [`try_lock_explicit_unchecked`](TryLock::try_lock_explicit_unchecked). #[inline] pubfn try_lock(&self) -> Option<Locked<T>> { unsafe { self.try_lock_explicit_unchecked(Ordering::Acquire, Ordering::Release)
}
}
/// Try to acquire the lock of this value using the lock and unlock orderings. /// /// If the lock is already acquired by someone else, this returns /// `None`. You can try to acquire again whenever you want, perhaps /// by spinning a few times, or by using some other means of /// notification. #[inline] #[deprecated(
since = "0.2.3",
note = "This method is actually unsafe because it unsafely allows \
the use of weaker memory ordering. Please use try_lock_explicit instead"
)] pubfn try_lock_order(&self, lock_order: Ordering, unlock_order: Ordering) -> Option<Locked<T>> { unsafe { self.try_lock_explicit_unchecked(lock_order, unlock_order)
}
}
/// Try to acquire the lock of this value using the specified lock and /// unlock orderings. /// /// If the lock is already acquired by someone else, this returns /// `None`. You can try to acquire again whenever you want, perhaps /// by spinning a few times, or by using some other means of /// notification. /// /// # Panic /// /// This method panics if `lock_order` is not any of `Acquire`, `AcqRel`, /// and `SeqCst`, or `unlock_order` is not any of `Release` and `SeqCst`. #[inline] pubfn try_lock_explicit(&self, lock_order: Ordering, unlock_order: Ordering) -> Option<Locked<T>> { match lock_order {
Ordering::Acquire |
Ordering::AcqRel |
Ordering::SeqCst => {}
_ => panic!("lock ordering must be `Acquire`, `AcqRel`, or `SeqCst`"),
}
match unlock_order {
Ordering::Release |
Ordering::SeqCst => {}
_ => panic!("unlock ordering must be `Release` or `SeqCst`"),
}
/// Try to acquire the lock of this value using the specified lock and /// unlock orderings without checking that the specified orderings are /// strong enough to be safe. /// /// If the lock is already acquired by someone else, this returns /// `None`. You can try to acquire again whenever you want, perhaps /// by spinning a few times, or by using some other means of /// notification. /// /// # Safety /// /// Unlike [`try_lock_explicit`], this method is unsafe because it does not /// check that the given memory orderings are strong enough to prevent data /// race. /// /// [`try_lock_explicit`]: Self::try_lock_explicit #[inline] pubunsafefn try_lock_explicit_unchecked(&self, lock_order: Ordering, unlock_order: Ordering) -> Option<Locked<T>> { if !self.is_locked.swap(true, lock_order) {
Some(Locked {
lock: self,
order: unlock_order,
_p: PhantomData,
})
} else {
None
}
}
/// Take the value back out of the lock when this is the sole owner. #[inline] pubfn into_inner(self) -> T {
debug_assert!(!self.is_locked.load(Ordering::Relaxed), "TryLock was mem::forgotten"); // Since the compiler can statically determine this is the only owner, // it's safe to take the value out. In fact, in newer versions of Rust, // `UnsafeCell::into_inner` has been marked safe. // // To support older version (1.21), the unsafe block is still here. #[allow(unused_unsafe)] unsafe { self.value.into_inner()
}
}
}
unsafeimpl<T: Send> Send for TryLock<T> {} unsafeimpl<T: Send> Sync for TryLock<T> {}
/// A locked value acquired from a `TryLock`. /// /// The type represents an exclusive view at the underlying value. The lock is /// released when this type is dropped. /// /// This type derefs to the underlying value. #[must_use = "TryLock will immediately unlock if not used"] pubstruct Locked<'a, T: 'a> {
lock: &'a TryLock<T>,
order: Ordering, /// Suppresses Send and Sync autotraits for `struct Locked`.
_p: PhantomData<*mut T>,
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.