#Beginners question regarding Send vs move

8 messages · Page 1 of 1 (latest)

rare mantle
#

I am learning rust and there is something I don't understand - I can imagine this is a common beginners failure, still I couldn't find an explanation to this specific issue but if it has been asked before I beg your pardon for my annoyance.
The issue comes with the following scenario: I have a struct containing an instance of a dyn trait that I would like to move to a thread. I do not want to share anything between threads but I would like to move the dyn trait instance to the thread, so that the thread owns the instance. This does not work, I get told that dyn Trait + 'static cannot be sent - but I don't understand why.
The scenario corresponds to the following example:

trait Trait {}
struct Struct {}
impl Trait for Struct {}

struct Contains {
    t: Box<dyn Trait>,
}

impl Contains {
    pub fn run (mut self) {}
}

fn main () {
    let c = Contains {
        t: Box::new (Struct {}),
    };

    let runner = std::thread::spawn (move || c.run ());

    runner.join ().unwrap ();
}

As I would assume the instance of c is moved to the thread and there is no sharing of it. This can be worked around if I put the instantiation into the closure but this can have other implications if for instance the instantiation of the struct involves cloning of other resources.
Furthermore this only happens if this involves a dyn trait, it works fine if there are only sized objects involved. Why?

candid oracle
#

The trait concerned with sharing is Sync. Send is specifically for moving something to a different thread. It's rare to not have Send for owned types, but some exist like MutexGuard and rand::ThreadRng. It's probably fine to just add Send to your trait object:

t: Box<dyn Trait + Send>,
rare mantle
#

Thanks! I have seen this and indeed this compiles but what worries me here is that when I look at the trait Send it says: "pub unsafe auto trait Send", so this already involves "unsafe"? I see, I misunderstood, so Send is for moving to threads and Sync is for sharing. But what does this unsafe mean?

#

And why is this only the case for dyn traits?

candid oracle
#

That means it's unsafe to manually implement Send, which you would only need to do if your struct contains a type that doesn't implement Send, and would indicate that you are somehow ensuring that whatever inner type that needs Send never observes another thread (maybe it's in an Option that is None except in specific circumstances, or maybe you check which thread you're on and panic when it's not the correct one).

It's not specific to trait objects. You need Send for anything that moves to another thread. If you had a generic function, you'd still need to add the Send bound.

rare mantle
#

Ahh, ok, thanks! So I guess the problem is Box which isn't Send by default?

candid oracle
#

No, nothing about Box. Trait objects aren't anything besides what you specify.

rare mantle
#

Aha, no I understand! Thank you!