pub unsafe auto trait Sync { }
Expand description
Types for which it is safe to share references between threads.
This trait is automatically implemented when the compiler determines it’s appropriate.
The precise definition is: a type T
is Sync
if and only if &T
is
Send
. In other words, if there is no possibility of
undefined behavior (including data races) when passing
&T
references between threads.
As one would expect, primitive types like u8
and f64
are all Sync
, and so are simple aggregate types containing them,
like tuples, structs and enums. More examples of basic Sync
types include “immutable” types like &T
, and those with simple
inherited mutability, such as Box<T>
, Vec<T>
and
most other collection types. (Generic parameters need to be Sync
for their container to be Sync
.)
A somewhat surprising consequence of the definition is that &mut T
is Sync
(if T
is Sync
) even though it seems like that might
provide unsynchronized mutation. The trick is that a mutable
reference behind a shared reference (that is, & &mut T
)
becomes read-only, as if it were a & &T
. Hence there is no risk
of a data race.
Types that are not Sync
are those that have “interior
mutability” in a non-thread-safe form, such as Cell
and RefCell
. These types allow for mutation of
their contents even through an immutable, shared reference. For
example the set
method on Cell<T>
takes &self
, so it requires
only a shared reference &Cell<T>
. The method performs no
synchronization, thus Cell
cannot be Sync
.
Another example of a non-Sync
type is the reference-counting
pointer Rc
. Given any reference &Rc<T>
, you can clone
a new Rc<T>
, modifying the reference counts in a non-atomic way.
For cases when one does need thread-safe interior mutability,
Rust provides atomic data types, as well as explicit locking via
sync::Mutex
and sync::RwLock
. These types
ensure that any mutation cannot cause data races, hence the types
are Sync
. Likewise, sync::Arc
provides a thread-safe
analogue of Rc
.
Any types with interior mutability must also use the
cell::UnsafeCell
wrapper around the value(s) which
can be mutated through a shared reference. Failing to doing this is
undefined behavior. For example, transmute
-ing
from &T
to &mut T
is invalid.
See the Nomicon for more details about Sync
.
Implementations on Foreign Types
impl Sync for Argument
impl Sync for FormatSpec
impl Sync for Alignment
impl Sync for Count
impl<T, F> Sync for SyncLazy<T, F> where
F: Send,
SyncOnceCell<T>: Sync,
impl<T> !Sync for Sender<T>
impl<'_, T> Sync for MutexGuard<'_, T> where
T: Sync + ?Sized,
impl<'a> Sync for IoSlice<'a>
impl<T> Sync for Key<T>
impl<'_, T> Sync for RwLockWriteGuard<'_, T> where
T: Sync + ?Sized,
impl !Sync for Args
impl<T> !Sync for Receiver<T>
impl<'a> Sync for IoSliceMut<'a>
impl<T> Sync for SyncOnceCell<T> where
T: Sync + Send,
impl !Sync for ArgsOs
impl<T> Sync for Mutex<T> where
T: Send + ?Sized,
impl Sync for Once
impl<T> Sync for JoinHandle<T>
impl<T> Sync for RwLock<T> where
T: Send + Sync + ?Sized,
impl<'_, T> Sync for RwLockReadGuard<'_, T> where
T: Sync + ?Sized,
impl Sync for AtomicU32
impl Sync for AtomicU8
impl Sync for AtomicIsize
impl<T> !Sync for RefCell<T> where
T: ?Sized,
impl<T> !Sync for *mut T where
T: ?Sized,
impl Sync for AtomicI64
impl<'_, T> Sync for IterMut<'_, T> where
T: Sync,
impl Sync for AtomicU64
impl Sync for AtomicU16
impl<T> Sync for SyncUnsafeCell<T> where
T: Sync + ?Sized,
impl Sync for Waker
impl<T> !Sync for NonNull<T> where
T: ?Sized,
NonNull
pointers are not Sync
because the data they reference may be aliased.
impl<T> !Sync for Cell<T> where
T: ?Sized,
impl Sync for AtomicI32
impl<T> !Sync for UnsafeCell<T> where
T: ?Sized,
impl<T> Sync for AtomicPtr<T>
impl Sync for AtomicUsize
impl Sync for AtomicI16
impl<'_, T> Sync for Iter<'_, T> where
T: Sync,
impl Sync for AtomicI8
impl<Dyn> Sync for DynMetadata<Dyn> where
Dyn: ?Sized,
impl<T> !Sync for *const T where
T: ?Sized,
impl Sync for AtomicBool
impl<T> !Sync for Weak<T> where
T: ?Sized,
impl<T> Sync for Arc<T> where
T: Sync + Send + ?Sized,
impl<T> Sync for Weak<T> where
T: Sync + Send + ?Sized,
impl<T> !Sync for Rc<T> where
T: ?Sized,
impl<'a, T, const CAP: usize> Sync for Drain<'a, T, CAP> where
T: Sync,
impl<'_, T, O> Sync for Drain<'_, T, O> where
T: BitStore,
O: BitOrder,
BitSlice<T, O>: Sync,
impl<T> Sync for BitSpanError<T> where
T: BitStore,
impl<T, O> Sync for BitBox<T, O> where
T: BitStore,
O: BitOrder,
impl<'_, M, T, O> Sync for BitRef<'_, M, T, O> where
M: Mutability,
T: BitStore + Sync,
O: BitOrder,
impl<T, O> Sync for IntoIter<T, O> where
T: BitStore + Sync,
O: BitOrder,
impl<'_, T, O> Sync for IterMut<'_, T, O> where
T: BitStore,
O: BitOrder,
BitSlice<T, O>: Sync,
impl<T, O> Sync for BitSlice<T, O> where
T: BitStore + Sync,
O: BitOrder,
Bit-Slice Thread Safety
This allows bit-slice references to be moved across thread boundaries only when
the underlying T
element can tolerate concurrency.
All BitSlice
references, shared or exclusive, are only threadsafe if the T
element type is Send
, because any given bit-slice reference may only have
partial control of a memory element that is also being shared by a bit-slice
reference on another thread. As such, this is never implemented for Cell<U>
,
but always implemented for AtomicU
and U
for a given unsigned integer type
U
.
Atomic integers safely handle concurrent writes, cells do not allow concurrency
at all, so the only missing piece is &mut BitSlice<_, U: Unsigned>
. This is
handled by the aliasing system that the mutable splitters employ: a mutable
reference to an unsynchronized bit-slice can only cross threads when no other
handle is able to exist to the elements it governs. Splitting a mutable
bit-slice causes the split halves to change over to either atomics or cells, so
concurrency is either safe or impossible.