// Copyright 2016 Amanieu d'Antras // // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or // http://opensource.org/licenses/MIT>, at your option. This file may not be // copied, modified, or distributed except according to those terms.
//! Generic `Atomic<T>` wrapper type //! //! Atomic types provide primitive shared-memory communication between //! threads, and are the building blocks of other concurrent types. //! //! This library defines a generic atomic wrapper type `Atomic<T>` for all //! `T: Copy` types. //! Atomic types present operations that, when used correctly, synchronize //! updates between threads. //! //! Each method takes an `Ordering` which represents the strength of //! the memory barrier for that operation. These orderings are the //! same as [LLVM atomic orderings][1]. //! //! [1]: http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations //! //! Atomic variables are safe to share between threads (they implement `Sync`) //! but they do not themselves provide the mechanism for sharing. The most //! common way to share an atomic variable is to put it into an `Arc` (an //! atomically-reference-counted shared pointer). //! //! Most atomic types may be stored in static variables, initialized using //! the `const fn` constructors (only available on nightly). Atomic statics //! are often used for lazy global initialization.
// Re-export some useful definitions from libcore pubuse core::sync::atomic::{fence, Ordering};
use core::cell::UnsafeCell; use core::fmt;
#[cfg(feature = "std")] use std::panic::RefUnwindSafe;
mod fallback; mod ops;
/// A generic atomic wrapper type which allows an object to be safely shared /// between threads. pubstruct Atomic<T: Copy> {
v: UnsafeCell<T>,
}
// Atomic<T> is only Sync if T is Send unsafeimpl<T: Copy + Send> Sync for Atomic<T> {}
// Given that atomicity is guaranteed, Atomic<T> is RefUnwindSafe if T is // // This is trivially correct for native lock-free atomic types. For those whose // atomicity is emulated using a spinlock, it is still correct because the // `Atomic` API does not allow doing any panic-inducing operation after writing // to the target object. #[cfg(feature = "std")] impl<T: Copy + RefUnwindSafe> RefUnwindSafe for Atomic<T> {}
/// Checks if `Atomic` objects of this type are lock-free. /// /// If an `Atomic` is not lock-free then it may be implemented using locks /// internally, which makes it unsuitable for some situations (such as /// communicating with a signal handler). #[inline] #[cfg(feature = "nightly")] pubconstfn is_lock_free() -> bool {
ops::atomic_is_lock_free::<T>()
}
/// Checks if `Atomic` objects of this type are lock-free. /// /// If an `Atomic` is not lock-free then it may be implemented using locks /// internally, which makes it unsuitable for some situations (such as /// communicating with a signal handler). #[inline] #[cfg(not(feature = "nightly"))] pubfn is_lock_free() -> bool {
ops::atomic_is_lock_free::<T>()
}
/// Returns a mutable reference to the underlying type. /// /// This is safe because the mutable reference guarantees that no other threads are /// concurrently accessing the atomic data. #[inline] pubfn get_mut(&mutself) -> &mut T { unsafe { &mut *self.v.get() }
}
/// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are /// concurrently accessing the atomic data. #[inline] pubfn into_inner(self) -> T { self.v.into_inner()
}
/// Loads a value from the `Atomic`. /// /// `load` takes an `Ordering` argument which describes the memory ordering /// of this operation. /// /// # Panics /// /// Panics if `order` is `Release` or `AcqRel`. #[inline] pubfn load(&self, order: Ordering) -> T { unsafe { ops::atomic_load(self.v.get(), order) }
}
/// Stores a value into the `Atomic`. /// /// `store` takes an `Ordering` argument which describes the memory ordering /// of this operation. /// /// # Panics /// /// Panics if `order` is `Acquire` or `AcqRel`. #[inline] pubfn store(&self, val: T, order: Ordering) { unsafe {
ops::atomic_store(self.v.get(), val, order);
}
}
/// Stores a value into the `Atomic`, returning the old value. /// /// `swap` takes an `Ordering` argument which describes the memory ordering /// of this operation. #[inline] pubfn swap(&self, val: T, order: Ordering) -> T { unsafe { ops::atomic_swap(self.v.get(), val, order) }
}
/// Stores a value into the `Atomic` if the current value is the same as the /// `current` value. /// /// The return value is a result indicating whether the new value was /// written and containing the previous value. On success this value is /// guaranteed to be equal to `new`. /// /// `compare_exchange` takes two `Ordering` arguments to describe the memory /// ordering of this operation. The first describes the required ordering if /// the operation succeeds while the second describes the required ordering /// when the operation fails. The failure ordering can't be `Acquire` or /// `AcqRel` and must be equivalent or weaker than the success ordering. #[inline] pubfn compare_exchange(
&self,
current: T,
new: T,
success: Ordering,
failure: Ordering,
) -> Result<T, T> { unsafe { ops::atomic_compare_exchange(self.v.get(), current, new, success, failure) }
}
/// Stores a value into the `Atomic` if the current value is the same as the /// `current` value. /// /// Unlike `compare_exchange`, this function is allowed to spuriously fail /// even when the comparison succeeds, which can result in more efficient /// code on some platforms. The return value is a result indicating whether /// the new value was written and containing the previous value. /// /// `compare_exchange` takes two `Ordering` arguments to describe the memory /// ordering of this operation. The first describes the required ordering if /// the operation succeeds while the second describes the required ordering /// when the operation fails. The failure ordering can't be `Acquire` or /// `AcqRel` and must be equivalent or weaker than the success ordering. /// success ordering. #[inline] pubfn compare_exchange_weak(
&self,
current: T,
new: T,
success: Ordering,
failure: Ordering,
) -> Result<T, T> { unsafe { ops::atomic_compare_exchange_weak(self.v.get(), current, new, success, failure) }
}
}
impl Atomic<bool> { /// Logical "and" with a boolean value. /// /// Performs a logical "and" operation on the current value and the argument /// `val`, and sets the new value to the result. /// /// Returns the previous value. #[inline] pubfn fetch_and(&self, val: bool, order: Ordering) -> bool { unsafe { ops::atomic_and(self.v.get(), val, order) }
}
/// Logical "or" with a boolean value. /// /// Performs a logical "or" operation on the current value and the argument /// `val`, and sets the new value to the result. /// /// Returns the previous value. #[inline] pubfn fetch_or(&self, val: bool, order: Ordering) -> bool { unsafe { ops::atomic_or(self.v.get(), val, order) }
}
/// Logical "xor" with a boolean value. /// /// Performs a logical "xor" operation on the current value and the argument /// `val`, and sets the new value to the result. /// /// Returns the previous value. #[inline] pubfn fetch_xor(&self, val: bool, order: Ordering) -> bool { unsafe { ops::atomic_xor(self.v.get(), val, order) }
}
}
macro_rules! atomic_ops_common {
($($t:ty)*) => ($( impl Atomic<$t> { /// Add to the current value, returning the previous value. #[inline] pubfn fetch_add(&self, val: $t, order: Ordering) -> $t { unsafe { ops::atomic_add(self.v.get(), val, order) }
}
/// Subtract from the current value, returning the previous value. #[inline] pubfn fetch_sub(&self, val: $t, order: Ordering) -> $t { unsafe { ops::atomic_sub(self.v.get(), val, order) }
}
/// Bitwise and with the current value, returning the previous value. #[inline] pubfn fetch_and(&self, val: $t, order: Ordering) -> $t { unsafe { ops::atomic_and(self.v.get(), val, order) }
}
/// Bitwise or with the current value, returning the previous value. #[inline] pubfn fetch_or(&self, val: $t, order: Ordering) -> $t { unsafe { ops::atomic_or(self.v.get(), val, order) }
}
/// Bitwise xor with the current value, returning the previous value. #[inline] pubfn fetch_xor(&self, val: $t, order: Ordering) -> $t { unsafe { ops::atomic_xor(self.v.get(), val, order) }
}
}
)*);
}
macro_rules! atomic_ops_signed {
($($t:ty)*) => (
atomic_ops_common!{ $($t)* }
$( impl Atomic<$t> { /// Minimum with the current value. #[inline] pubfn fetch_min(&self, val: $t, order: Ordering) -> $t { unsafe { ops::atomic_min(self.v.get(), val, order) }
}
/// Maximum with the current value. #[inline] pubfn fetch_max(&self, val: $t, order: Ordering) -> $t { unsafe { ops::atomic_max(self.v.get(), val, order) }
}
}
)*
);
}
macro_rules! atomic_ops_unsigned {
($($t:ty)*) => (
atomic_ops_common!{ $($t)* }
$( impl Atomic<$t> { /// Minimum with the current value. #[inline] pubfn fetch_min(&self, val: $t, order: Ordering) -> $t { unsafe { ops::atomic_umin(self.v.get(), val, order) }
}
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.