Thread Safety in Rust: Send and Sync
Thread safety markers determine how types can cross thread boundaries:
- Send: A type
TisSendif its ownership can be transferred to another thread. - Sync: A type
TisSyncif its shared reference is of typeSend(i.e.,TisSyncif&TisSend).
All primitive types are Send and Sync. Types are automatically Send and Sync if all of their fields are Send and Sync.
Send
A type T is Send if its ownership can be transferred to another thread.
e.g., Arc<T> is Send, but Rc<T> is not.
Sync
A type T is Sync if its shared reference is of type Send (i.e., T is Sync if &T is Send).
e.g., i32 is Sync, but Cell<i32> is not Sync.
All primitive types are Send and Sync.
Auto Traits
Auto traits are traits which are implemented for a type if all of its fields implement them.
i.e.
struct User {
id: i32,
}
Here, User is both Send and Sync because id is Send and Sync.
To opt out, you can add a property that's not Send or Sync, like a Cell:
use std::cell::Cell;
use std::marker::PhantomData;
struct User {
id: i32,
__not_sync: PhantomData<Cell<()>>,
}
Now User is not Sync or Send.
Raw pointers like *const T and *mut T are neither Send nor Sync as the compiler cannot guarantee thread safety for them.
struct Org {
user: *mut usize,
}
unsafe impl Send for Org {}
unsafe impl Sync for Org {}
We need to use unsafe because the compiler can't guarantee that the value the user references is Send or Sync.
