pub struct SyncCell<T: ?Sized>(/* private fields */);Expand description
A mutable memory location that is Sync.
§Memory layout
SyncCell<T> has the same memory layout and caveats as Cell<T>, but it
is Sync if T is. In particular, since Cell<T> has the same
in-memory representation as its inner type T, SyncCell<T>, too, has the
same in-memory representation as its inner type T. SyncCell<T> is also
Send if Cell<T> is Send.
SyncCell<T> is useful when you need to share a mutable memory location
across threads, and you rely on the fact that the intended behavior will not
cause data races. For example, the content will be written once and then
read many times, in this order.
The main goal of SyncCell<T> is to make it possible to write to
different locations of a slice in parallel, leaving the control of data
races to the user, without the access cost of an atomic variable. For this
purpose, SyncCell implements the as_slice_of_cells method, which
turns a &SyncCell<[T]> into a &[SyncCell<T>], similar to the analogous
method of Cell.
Since this is the most common usage, the extension trait SyncSlice adds
to slices a method as_sync_slice that turns a &mut [T] into a
&[SyncCell<T>].
§Methods
SyncCell painstakingly reimplements the methods of Cell as unsafe,
since they rely on external synchronization mechanisms to avoid undefined
behavior.
SyncCell implements also a few traits implemented by Cell by
delegation for convenience, but some, such as Clone or PartialOrd,
cannot be implemented because they would use unsafe methods. The Debug
implementation is opaque, as reading the contained value would require
external synchronization.
§Safety
Multiple threads can read from and write to the same SyncCell at the same
time. It is the responsibility of the user to ensure that there are no data
races, which would cause undefined behavior.
Moreover, the methods that move or copy values in or out of a cell
(get, set, swap, replace, and take) can transfer a
value of type T to a different thread: if T is not Send, the
caller must ensure that such values are not moved to, copied to, or
dropped by, a thread different from the thread owning them.
§Examples
In this example, you can see that SyncCell enables mutation across
threads:
use sync_cell_slice::SyncCell;
use sync_cell_slice::SyncSlice;
let x = 0;
let c = SyncCell::new(x);
let mut v = vec![1, 2, 3, 4];
let s = v.as_sync_slice();
std::thread::scope(|scope| {
scope.spawn(|| {
// You can use interior mutability in another thread
unsafe { c.set(5) };
});
scope.spawn(|| {
// You can use interior mutability in another thread
unsafe { s[0].set(5) };
});
scope.spawn(|| {
// You can use interior mutability in another thread
// on the same slice
unsafe { s[1].set(10) };
});
});In this example, we invert a permutation in parallel:
use sync_cell_slice::SyncCell;
use sync_cell_slice::SyncSlice;
let mut perm = vec![0, 2, 3, 1];
let mut inv = vec![0; perm.len()];
let inv_sync = inv.as_sync_slice();
std::thread::scope(|scope| {
scope.spawn(|| { // Invert first half
for i in 0..2 {
unsafe { inv_sync[perm[i]].set(i) };
}
});
scope.spawn(|| { // Invert second half
for i in 2..perm.len() {
unsafe { inv_sync[perm[i]].set(i) };
}
});
});
assert_eq!(inv, vec![0, 3, 1, 2]);Implementations§
Source§impl<T> SyncCell<T>
impl<T> SyncCell<T>
Sourcepub unsafe fn set(&self, val: T)
pub unsafe fn set(&self, val: T)
Sets the contained value by delegation to Cell::set.
§Safety
Multiple threads can read from and write to the same SyncCell at the
same time. It is the responsibility of the user to ensure that there are no
data races, which would cause undefined behavior.
Moreover, this method drops the previously contained value: if T is
not Send, the caller must ensure that the calling thread owns that
value.
Sourcepub unsafe fn swap(&self, other: &SyncCell<T>)
pub unsafe fn swap(&self, other: &SyncCell<T>)
Swaps the values of two SyncCells by delegation to Cell::swap.
§Panics
This method panics if self and other are different cells that
partially overlap (see Cell::swap).
§Safety
Multiple threads can read from and write to the same SyncCell at the
same time. It is the responsibility of the user to ensure that there are no
data races, which would cause undefined behavior.
Moreover, this method moves the contained values between cells: if T
is not Send, the caller must ensure that the calling thread owns
both values.
Sourcepub unsafe fn replace(&self, val: T) -> T
pub unsafe fn replace(&self, val: T) -> T
Replaces the contained value with val, and returns the old contained
value by delegation to Cell::replace.
§Safety
Multiple threads can read from and write to the same SyncCell at the
same time. It is the responsibility of the user to ensure that there are no
data races, which would cause undefined behavior.
Moreover, this method returns the previously contained value: if T is
not Send, the caller must ensure that the calling thread owns that
value.
Sourcepub fn into_inner(self) -> T
pub fn into_inner(self) -> T
Unwraps the value, consuming the cell.
Source§impl<T: Copy> SyncCell<T>
impl<T: Copy> SyncCell<T>
Sourcepub unsafe fn get(&self) -> T
pub unsafe fn get(&self) -> T
Returns a copy of the contained value by delegation to Cell::get.
§Safety
Multiple threads can read from and write to the same SyncCell at the
same time. It is the responsibility of the user to ensure that there are no
data races, which would cause undefined behavior.
Moreover, this method returns a copy of the contained value: if T is
not Send, the caller must ensure that the copy is not used by a
thread different from the thread owning the original value.
Source§impl<T: ?Sized> SyncCell<T>
impl<T: ?Sized> SyncCell<T>
Sourcepub const fn as_ptr(&self) -> *mut T
pub const fn as_ptr(&self) -> *mut T
Returns a raw pointer to the underlying data in this cell
by delegation to Cell::as_ptr.
Dereferencing the returned pointer requires unsafe code: multiple
threads can read from and write to the same SyncCell at the same
time, and it is the responsibility of the user to ensure that there
are no data races, which would cause undefined behavior.
Sourcepub fn get_mut(&mut self) -> &mut T
pub fn get_mut(&mut self) -> &mut T
Returns a mutable reference to the underlying data by delegation to
Cell::get_mut.
Source§impl<T: Default> SyncCell<T>
impl<T: Default> SyncCell<T>
Sourcepub unsafe fn take(&self) -> T
pub unsafe fn take(&self) -> T
Takes the value of the cell, leaving Default::default in its place.
§Safety
Multiple threads can read from and write to the same SyncCell at the
same time. It is the responsibility of the user to ensure that there are no
data races, which would cause undefined behavior.
Moreover, this method returns the previously contained value: if T is
not Send, the caller must ensure that the calling thread owns that
value.