Send & Sync
There are two special traits in Rust for concurrency semantics.
Send
marks a structure safe to send between threads.Sync
marks a structure safe to share between threads.- (
&T
isSend
)
- (
These traits are what Rust uses to prevent data races.
They are automatically derived for all types if appropriate.
Automatically Derived
use std::thread; #[derive(Debug)] struct Thing; // Can send between threads! fn main() { let thing = Thing; thread::spawn(move || { println!("{:?}", thing); }).join().unwrap(); }
There are some notable types which are not Send
or Sync
.
Such as Rc
, raw pointers, and UnsafeCell
.
Example: Rc
use std::rc::Rc;
use std::thread;
// Does not work!
fn main() {
let value = Rc::new(true);
thread::spawn(move || {
println!("{:?}", value);
}).join().unwrap();
}
Example: Rc
error[E0277]: `Rc<bool>` cannot be sent between threads safely
--> src/main.rs:7:19
|
7 | thread::spawn(move || {
| ------------- ^------
| | |
| _____|_____________within this `{closure@src/main.rs:7:19: 7:26}`
| | |
| | required by a bound introduced by this call
8 | | println!("{:?}", value);
9 | | }).join().unwrap();
| |_____^ `Rc<bool>` cannot be sent between threads safely
|
= help: within `{closure@src/main.rs:7:19: 7:26}`, the trait `Send` is not implemented for `Rc<bool>`, which is required by `{closure@src/main.rs:7:19: 7:26}: Send`
note: required because it's used within this closure
--> src/main.rs:7:19
|
7 | thread::spawn(move || {
| ^^^^^^^
note: required by a bound in `spawn`
--> /home/mrg/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/mod.rs:675:8
|
672 | pub fn spawn<F, T>(f: F) -> JoinHandle<T>
| ----- required by a bound in this function
...
675 | F: Send + 'static,
| ^^^^ required by this bound in `spawn`
For more information about this error, try `rustc --explain E0277`.
Implementing
It's possible to add the implementation of Send
and Sync
to a type.
#![allow(unused)] fn main() { struct Thing(*mut String); unsafe impl Send for Thing {} unsafe impl Sync for Thing {} }
In these cases, the task of thread safety is left to the implementor.
Relationships
If a type implements both Sync
and Copy
then it can also implement Send
.
Relationships
A type &T
can implement Send
if the type T
also implements Sync
.
unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {}
Relationships
A type &mut T
can implement Send
if the type T
also implements Send
.
unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
Consequences
What are the consequences of having Send
and Sync
?
Consequences
Carrying this information at the type system level allows driving data race bugs down to a compile time level.
Preventing this error class from reaching production systems.
Send
and Sync
are independent of the choice of concurrency (async, threaded, etc.).