Send and Sync
-
SendandSyncare traits. -
SendandSyncare 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:
Copyis a marker trait that tells the compiler that the type can beCloned using a bitwise copy. -
Example:
Sizedis a marker trait that tells the compiler that values of typeThave a size known at compile time.
-
SendandSyncare auto traits.- Auto traits are automatically implemented for types if possible.
-
For example, a struct
Tautomatically implementsSendif all the fields ofTimplementSend.
Send
-
A type
TisSendif values of typeTare 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
TisSyncif values of typeTcan 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
TisSyncif and only if&TisSend.
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
Sendbecause updating the reference count is not atomic -
Not
SyncbecauseRc::clonetakes&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>.
-
SendifT: Send. -
Not
Syncbecause 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
-
SyncifT: Sync. -
Not
Sendbecause-
On certain operating systems, the
std::sync::Muteximplementation 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
-
SendifT: Send. -
SyncifT: Sendbecause-
A
Mutex<T>allows you to get a&mut Tthrough 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 aTon 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
-
SendifT: Send + Sync.-
T: Syncis required becauseArc<T>::deref(&self)returns a&T.
-
-
SyncifT: Send + Sync.-
T: Sendis required becausepub fn try_unwrap(this: Arc<T, A>) -> Result<T, Arc<T, A>>Allows getting a
Tifthisis the only strong reference left, movingTacross threads.
-