Function show_notes::e022::demo_send_and_sync

source ·
pub fn demo_send_and_sync()
Expand description

How Send and Sync work

Here we have a function which spawns a thread to run println!(). This is silly, of course, but it works because (and only because!) String implements the Send trait.

pub fn demo_send() {
    let foo = String::from("Hallo!");
    thread::spawn(move || {
        println!("{}", foo);
    });
}

If we had a *non-Send type here – e.g. an Rc<String> instead of just a String – we would get a compiler error:

pub fn will_fail() {
    let foo = Rc::new(String::from("Hallo!"));
    thread::spawn(|| {
        println!("{:?}", foo);
    });
}

Instead, you’ll get a compiler error:

error[E0277]: the trait bound `std::rc::Rc<std::string::String>: std::marker::Sync` is not satisfied
   --> src/e022.rs:214:5    |
214 |     thread::spawn(|| {
    |     ^^^^^^^^^^^^^ `std::rc::Rc<std::string::String>` cannot be shared between threads safely
    |
    = help: the trait `std::marker::Sync` is not implemented for `std::rc::Rc<std::string::String>`
    = note: required because of the requirements on the impl of `std::marker::Send` for `&std::rc::Rc<std::string::String>`
    = note: required because it appears within the type `[closure@src/e022.rs:214:19: 216:6 foo:&std::rc::Rc<std::string::String>]`
    = note: required by `std::thread::spawn`

Notice that it’s common to see those errors together, and notice moreover that the error here includes both Send and Sync. The compiler tries to see if foo can be taken via reference, but the Rc type is not Sync, i.e. you cannot share references to it across threads, and that’s so because it is not Send. (Strictly speaking, all Sync types are Send, but not all Send types must be Sync, though off the top of my head I can’t think of a scenario where a type would be Send but not also Sync.)

What’s somewhat curious is that there really isn’t a lot more than this to demo here! To get into anything more interesting in terms of implementation related to these traits, we’d have to be off in unsafe land, and we haven’t talked about unsafe at all yet, so we’re not going to do that today. However, if you want to see a good example of what makes for code that can be safely shared across threads, take a look at the implementation of Vec and the RawVec type it’s built on! Reading the standard library is a really good way to learn things about Rust, and it’s surprisingly straightforward most of the time.