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 is Send)

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.).