Send and Sync
-
Send
andSync
are traits. -
Send
andSync
are marker traits.- Marker traits are used to indicate to the compiler of some property.
- Marker traits usually do not enforce any associated types or methods.
-
Example:
Copy
is a marker trait that tells the compiler that the type can beClone
d using a bitwise copy. -
Example:
Sized
is a marker trait that tells the compiler that values of typeT
have a size known at compile time.
-
Send
andSync
are auto traits.- Auto traits are automatically implemented for types if possible.
-
For example, a struct
T
automatically implementsSend
if all the fields ofT
implementSend
.
Send
-
A type
T
isSend
if values of typeT
are safe to send to another thread. - Sending refers to transferring ownership, or moving the value to the new thread.
fn is_send<T: Send>(_val: T) {}
fn main() {
let x = 8;
std::thread::spawn(move || {
dbg!(x);
});
is_send(x);
}
Most types are Send
.
Sync
-
A type
T
isSync
if values of typeT
can be shared by other threads. - Sharing refers to accessing the value via reference among multiple threads.
fn is_sync<T: Sync>(_val: T) {}
fn main() {
let x = 8;
std::thread::scope(|s| {
s.spawn(|| {
dbg!(x);
});
});
is_sync(x);
}
Send and Sync
T
isSync
if and only if&T
isSend
.
fn is_send<T: Send>(_val: T) {
println!("{} is Send", std::any::type_name::<T>());
}
fn is_sync<T: Sync>(_val: T) {
println!("{} is Sync", std::any::type_name::<T>());
}
fn main() {
let x = 8;
is_sync(x);
is_send(&x);
}
Not Send
and Not Sync
-
Raw pointers:
*const T
,*mut T
- Semantic reason, up to programmer to ensure proper usage of the pointers.
-
Reference counting pointer:
Rc<T>
-
Not
Send
because updating the reference count is not atomic -
Not
Sync
becauseRc::clone
takes&self
, which updates the reference count
-
Not
Not Sync
Types that are not Sync
usually provide single-threaded interior mutability, like Cell<T>
and RefCell<T>
.
-
Send
ifT: Send
. -
Not
Sync
because interior mutability can be done with a&self
.
use std::cell::Cell;
fn main() {
let cell = Cell::new(5);
std::thread::spawn(|| {
cell.set(6);
});
std::thread::spawn(|| {
cell.set(7);
});
}
Not Send
The MutexGuard<T>
type is
-
Sync
ifT: Sync
. -
Not
Send
because-
On certain operating systems, the
std::sync::Mutex
implementation uses POSIX threads (pthreads) mutexes under the hood. - Pthread mutexes require unlocking a mutex on the same thread that locked the mutex.
-
Since mutexes are unlocked in Rust by dropping the
MutexGuard<T>
, the guard cannot be sent to another thread.
-
On certain operating systems, the
Sometimes Send
or Sync
The Mutex<T>
type is
-
Send
ifT: Send
. -
Sync
ifT: Send
because-
A
Mutex<T>
allows you to get a&mut T
through a&Mutex<T>
. -
We can take ownership through mutable references.
-
For example,
Option<T>
haspub fn take(&mut self) -> Option<T>
. -
If
T: !Send
, thenOption<T>: !Send
, -
…so if
Mutex<T>
is stillSync
, we can get aT
on a different thread given a&Mutex<T>
, which is a contradiction.
-
For example,
-
A
Question: Why does Mutex<T>: Sync
not require T: Sync
?
Sometimes Send
or Sync
(2)
The Arc<T>
type is
-
Send
ifT: Send + Sync
.-
T: Sync
is required becauseArc<T>::deref(&self)
returns a&T
.
-
-
Sync
ifT: Send + Sync
.-
T: Send
is required becausepub fn try_unwrap(this: Arc<T, A>) -> Result<T, Arc<T, A>>
Allows getting a
T
ifthis
is the only strong reference left, movingT
across threads.
-