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 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 is Send)
These traits are what Rust uses to prevent data races.
They are automatically derived for all types if appropriate.
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.
Rcuse std::rc::Rc;
use std::thread;
// Does not work!
fn main() {
let only_one_thread = Rc::new(true);
thread::spawn(move || {
println!("{:?}", only_one_thread);
}).join().unwrap();
}Rcerror[E0277]: the trait bound `std::rc::Rc<bool>: std::marker::Send` is not satisfied
--> <anon>:7:5
|
7 | thread::spawn(move || {
| ^^^^^^^^^^^^^ the trait `std::marker::Send` is not implemented for `std::rc::Rc<bool>`It’s possible to add the implementation of Send and Sync to a type.
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.
If a type implements both Sync and Copy then it can also implement Send.
A type &T can implement Send if the type T also implements Sync.
unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {}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 {}What are the consequences of having Send and Sync?
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.).