pub struct Atomic<T: Atom>(/* private fields */);
Expand description
The main type of this library: a generic atomic type.
Via the methods of this type you can perform various atomic operations. You
can use any type T
that implements Atom
. This includes primitive
atomics (the ones found in std::sync::atomic
), other primitive types and
potentially your own types. Additional methods are usable if T
implements
AtomLogic
or AtomInteger
.
All methods use Atom::pack
and Atom::unpack
to convert between the
underlying atomic value and the real value T
. For types that implement
PrimitiveAtom
, these two methods are a simple ID
function, meaning that there is no runtime overhead. Other types should
make sure their pack
and unpack
operations are fast, as they are used a
lot in this type.
For all methods that do a comparison (e.g. compare_exchange
), keep in
mind that the comparison is performed on the bits of the underlying type
which can sometimes lead to unexpected behavior. For example, for floats,
there are many bit patterns that represent NaN. So the atomic might indeed
store a NaN representation at a moment, but compare_exchange
called with
current = NaN
might not swap, because both NaN differ in the bit
representation.
The interface of this type very closely matches the interface of the atomic
types in std::sync::atomic
. The documentation was copied (and slightly
adjusted) from there.
Implementations§
source§impl<T: Atom> Atomic<T>
impl<T: Atom> Atomic<T>
sourcepub const fn from_impl(v: <<T as Atom>::Repr as PrimitiveAtom>::Impl) -> Self
pub const fn from_impl(v: <<T as Atom>::Repr as PrimitiveAtom>::Impl) -> Self
Creates a new atomic value from the underlying Atomic*
type from std
.
Since Atom
is a trait
and const fn
s in trait
s are not supported yet,
the only way for this to be a const fn
is
to take the underyling atomic impl type directly.
This allows static
Atomic
s to be created.
§Examples
use atomig::Atomic;
use std::sync::atomic::AtomicU32;
static X: Atomic<u32> = Atomic::from_impl(AtomicU32::new(7));
sourcepub fn into_inner(self) -> T
pub fn into_inner(self) -> T
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.
sourcepub fn load(&self, order: Ordering) -> T
pub fn load(&self, order: Ordering) -> T
Loads the value from the atomic.
load
takes an Ordering
argument which describes the memory
ordering of this operation. Possible values are SeqCst
, Acquire
and
Relaxed
.
§Panics
Panics if order
is Release
or AcqRel
.
§Examples
use atomig::{Atomic, Ordering};
let x = Atomic::new(5);
assert_eq!(x.load(Ordering::SeqCst), 5);
sourcepub fn store(&self, v: T, order: Ordering)
pub fn store(&self, v: T, order: Ordering)
Stores a value into the atomic.
store
takes an Ordering
argument which describes the memory
ordering of this operation. Possible values are SeqCst
, Release
and
Relaxed
.
§Panics
Panics if order
is Acquire
or AcqRel
.
§Examples
use atomig::{Atomic, Ordering};
let x = Atomic::new(5);
x.store(10, Ordering::SeqCst);
assert_eq!(x.load(Ordering::SeqCst), 10);
sourcepub fn swap(&self, v: T, order: Ordering) -> T
pub fn swap(&self, v: T, order: Ordering) -> T
Stores a value into the atomic, returning the previous value.
swap
takes an Ordering
argument which describes the memory
ordering of this operation. All ordering modes are possible. Note that
using Acquire
makes the store part of this operation Relaxed
, and
using Release
makes the load part Relaxed
.
§Examples
use atomig::{Atomic, Ordering};
let x = Atomic::new(5);
assert_eq!(x.swap(10, Ordering::SeqCst), 5);
sourcepub fn compare_exchange(
&self,
current: T,
new: T,
success: Ordering,
failure: Ordering
) -> Result<T, T>
pub fn compare_exchange( &self, current: T, new: T, success: Ordering, failure: Ordering ) -> Result<T, T>
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 current
.
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. Using Acquire
as success
ordering makes the store part of this operation Relaxed
, and using
Release
makes the successful load Relaxed
. The failure ordering can
only be SeqCst
, Acquire
or Relaxed
and must be equivalent to or
weaker than the success ordering.
§Examples
use atomig::{Atomic, Ordering};
let x = Atomic::new(5);
assert_eq!(
x.compare_exchange(5, 10, Ordering::Acquire, Ordering::Relaxed),
Ok(5),
);
assert_eq!(x.load(Ordering::Relaxed), 10);
assert_eq!(
x.compare_exchange(6, 12, Ordering::SeqCst, Ordering::Acquire),
Err(10),
);
assert_eq!(x.load(Ordering::Relaxed), 10);
sourcepub fn compare_exchange_weak(
&self,
current: T,
new: T,
success: Ordering,
failure: Ordering
) -> Result<T, T>
pub fn compare_exchange_weak( &self, current: T, new: T, success: Ordering, failure: Ordering ) -> Result<T, T>
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_weak
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. Using Acquire
as success
ordering makes the store part of this operation Relaxed
, and using
Release
makes the successful load Relaxed
. The failure ordering can
only be SeqCst
, Acquire
or Relaxed
and must be equivalent to or
weaker than the success ordering.
§Examples
use atomig::{Atomic, Ordering};
let x = Atomic::new(4);
let mut old = x.load(Ordering::Relaxed);
loop {
let new = old * 2;
match x.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
Ok(_) => break,
Err(x) => old = x,
}
}
sourcepub fn fetch_update<F>(
&self,
set_order: Ordering,
fetch_order: Ordering,
f: F
) -> Result<T, T>
pub fn fetch_update<F>( &self, set_order: Ordering, fetch_order: Ordering, f: F ) -> Result<T, T>
Fetches the value, and applies a function to it that returns an
optional new value. Returns a Result
of Ok(previous_value)
if the
function returned Some(_)
, else Err(previous_value)
.
Note: This may call the function multiple times if the value has been
changed from other threads in the meantime, as long as the function
returns Some(_)
, but the function will have been applied but once to
the stored value.
fetch_update
takes two Ordering
arguments to describe the memory
ordering of this operation. The first describes the required ordering
for loads and failed updates while the second describes the required
ordering when the operation finally succeeds. Beware that this is
different from the two modes in compare_exchange
!
Using Acquire
as success ordering makes the store part of this
operation Relaxed
, and using Release
makes the final successful
load Relaxed
. The (failed) load ordering can only be SeqCst
,
Acquire
or Relaxed
and must be equivalent to or weaker than the
success ordering.
§Examples
use atomig::{Atomic, Ordering};
let x = Atomic::new(7);
assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7));
assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7));
assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8));
assert_eq!(x.load(Ordering::SeqCst), 9);
source§impl<T: AtomLogic> Atomic<T>where
T::Repr: PrimitiveAtomLogic,
impl<T: AtomLogic> Atomic<T>where
T::Repr: PrimitiveAtomLogic,
sourcepub fn fetch_and(&self, val: T, order: Ordering) -> T
pub fn fetch_and(&self, val: T, order: Ordering) -> T
Bitwise “and” with the current value.
Performs a bitwise “and” operation on the current value and the
argument val
, and sets the new value to the result.
Returns the previous value.
fetch_and
takes an Ordering
argument which describes the memory
ordering of this operation. All ordering modes are possible. Note that
using Acquire
makes the store part of this operation Relaxed
, and
using Release
makes the load part Relaxed
.
Examples
use atomig::{Atomic, Ordering};
let x = Atomic::new(0b101101);
assert_eq!(x.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
assert_eq!(x.load(Ordering::SeqCst), 0b100001);
sourcepub fn fetch_nand(&self, val: T, order: Ordering) -> T
pub fn fetch_nand(&self, val: T, order: Ordering) -> T
Bitwise “nand” with the current value.
Performs a bitwise “nand” operation on the current value and the
argument val
, and sets the new value to the result.
Returns the previous value.
fetch_nand
takes an Ordering
argument which describes the memory
ordering of this operation. All ordering modes are possible. Note that
using Acquire
makes the store part of this operation Relaxed
, and
using Release
makes the load part Relaxed
.
Examples
use atomig::{Atomic, Ordering};
let x = Atomic::new(0x13);
assert_eq!(x.fetch_nand(0x31, Ordering::SeqCst), 0x13);
assert_eq!(x.load(Ordering::SeqCst), !(0x13 & 0x31));
sourcepub fn fetch_or(&self, val: T, order: Ordering) -> T
pub fn fetch_or(&self, val: T, order: Ordering) -> T
Bitwise “or” with the current value.
Performs a bitwise “or” operation on the current value and the
argument val
, and sets the new value to the result.
Returns the previous value.
fetch_or
takes an Ordering
argument which describes the memory
ordering of this operation. All ordering modes are possible. Note that
using Acquire
makes the store part of this operation Relaxed
, and
using Release
makes the load part Relaxed
.
Examples
use atomig::{Atomic, Ordering};
let x = Atomic::new(0b101101);
assert_eq!(x.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
assert_eq!(x.load(Ordering::SeqCst), 0b111111);
sourcepub fn fetch_xor(&self, val: T, order: Ordering) -> T
pub fn fetch_xor(&self, val: T, order: Ordering) -> T
Bitwise “xor” with the current value.
Performs a bitwise “xor” operation on the current value and the
argument val
, and sets the new value to the result.
Returns the previous value.
fetch_xor
takes an Ordering
argument which describes the memory
ordering of this operation. All ordering modes are possible. Note that
using Acquire
makes the store part of this operation Relaxed
, and
using Release
makes the load part Relaxed
.
Examples
use atomig::{Atomic, Ordering};
let x = Atomic::new(0b101101);
assert_eq!(x.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
assert_eq!(x.load(Ordering::SeqCst), 0b011110);
source§impl<T: AtomInteger> Atomic<T>where
T::Repr: PrimitiveAtomInteger,
impl<T: AtomInteger> Atomic<T>where
T::Repr: PrimitiveAtomInteger,
sourcepub fn fetch_add(&self, val: T, order: Ordering) -> T
pub fn fetch_add(&self, val: T, order: Ordering) -> T
Adds to the current value, returning the previous value.
This operation wraps around on overflow.
fetch_add
takes an Ordering
argument which describes the memory
ordering of this operation. All ordering modes are possible. Note that
using Acquire
makes the store part of this operation Relaxed
, and
using Release
makes the load part Relaxed
.
§Examples
use atomig::{Atomic, Ordering};
let x = Atomic::new(0);
assert_eq!(x.fetch_add(10, Ordering::SeqCst), 0);
assert_eq!(x.load(Ordering::SeqCst), 10);
sourcepub fn fetch_sub(&self, val: T, order: Ordering) -> T
pub fn fetch_sub(&self, val: T, order: Ordering) -> T
Subtracts from the current value, returning the previous value.
This operation wraps around on overflow.
fetch_sub
takes an Ordering
argument which describes the memory
ordering of this operation. All ordering modes are possible. Note that
using Acquire
makes the store part of this operation Relaxed
, and
using Release
makes the load part Relaxed
.
§Examples
use atomig::{Atomic, Ordering};
let x = Atomic::new(20);
assert_eq!(x.fetch_sub(10, Ordering::SeqCst), 20);
assert_eq!(x.load(Ordering::SeqCst), 10);
sourcepub fn fetch_max(&self, val: T, order: Ordering) -> T
pub fn fetch_max(&self, val: T, order: Ordering) -> T
Maximum with the current value.
Finds the maximum of the current value and the argument val
, and sets
the new value to the result.
Returns the previous value.
fetch_max
takes an Ordering
argument which describes the memory
ordering of this operation. All ordering modes are possible. Note that
using Acquire
makes the store part of this operation Relaxed
, and
using Release
makes the load part Relaxed
.
§Examples
use atomig::{Atomic, Ordering};
let foo = Atomic::new(23);
assert_eq!(foo.fetch_max(42, Ordering::SeqCst), 23);
assert_eq!(foo.load(Ordering::SeqCst), 42);
If you want to obtain the maximum value in one step, you can use the following:
use atomig::{Atomic, Ordering};
let foo = Atomic::new(23);
let bar = 42;
let max_foo = foo.fetch_max(bar, Ordering::SeqCst).max(bar);
assert!(max_foo == 42);
sourcepub fn fetch_min(&self, val: T, order: Ordering) -> T
pub fn fetch_min(&self, val: T, order: Ordering) -> T
Minimum with the current value.
Finds the minimum of the current value and the argument val
, and sets
the new value to the result.
Returns the previous value.
fetch_min
takes an Ordering
argument which describes the memory
ordering of this operation. All ordering modes are possible. Note that
using Acquire
makes the store part of this operation Relaxed
, and
using Release
makes the load part Relaxed
.
§Examples
use atomig::{Atomic, Ordering};
let foo = Atomic::new(23);
assert_eq!(foo.fetch_min(42, Ordering::Relaxed), 23);
assert_eq!(foo.load(Ordering::Relaxed), 23);
assert_eq!(foo.fetch_min(22, Ordering::Relaxed), 23);
assert_eq!(foo.load(Ordering::Relaxed), 22);
If you want to obtain the minimum value in one step, you can use the following:
use atomig::{Atomic, Ordering};
let foo = Atomic::new(23);
let bar = 12;
let min_foo = foo.fetch_min(bar, Ordering::SeqCst).min(bar);
assert!(min_foo == 12);