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, if Cell<T> has the same in-memory
representation as its inner type T, then SyncCell<T> has the same
in-memory representation as its inner type T (but the code does not rely
on this). 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 that of 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.
§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.
§Examples
In this example, you can see that SyncCell enables mutation across
threads:
use sync_cell_slice::SyncCell;
use sync_cell_slice::SyncSlice;
let mut 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 swap(&self, other: &SyncCell<T>)
pub unsafe fn swap(&self, other: &SyncCell<T>)
Swaps the values of two SyncCells by delegation to 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.
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.
Sourcepub fn into_inner(self) -> T
pub fn into_inner(self) -> T
Unwraps the value, consuming the cell.
Source§impl<T: ?Sized> SyncCell<T>
impl<T: ?Sized> SyncCell<T>
Sourcepub const unsafe fn as_ptr(&self) -> *mut T
pub const unsafe fn as_ptr(&self) -> *mut T
Returns a raw pointer to the underlying data in this cell
by delegation to Cell::as_ptr.
§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.
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.