Why &mut T : Send requires T: Send?

Cant figure out why it is necessary. &mut T is the only one allowed to access T, which ensures no races already.

Then what the additional T:Send is for?

1 Like

The T can have something called "thread-local" data. Essentially, it has access to some data which is local to one thread and may not be accessed by another thread. Thus, even though you have exclusive access to that T, you cannot "send" it to another thread. Hence, Rust ensures that via this impl: impl<T> Send for &mut T where T: Send. As long as the actual type is clear to be sent across threads, once you have exclusive access, you can send the pointer (reference in this case) as well.

1 Like

Mutable access allows you to move the referent by-value. E.g.:

struct NotSend(*const ());

fn main() {
    let mut x: NotSend = NotSend(core::ptr::null());
    let ptr: &mut NotSend = &mut x;
    
    std::thread::spawn(|| {
        let local = NotSend(core::ptr::null());
        let oops_moved_to_another_thread = core::mem::replace(ptr, local);
    });
}

This shouldn't compile (and indeed it doesn't).

6 Likes

You don't even need mem::replace (which looks special) -- *ptr = local will also cross threads.

2 Likes

The Send trait is not really about ownership transfers. I gave a summary that I quite like that explains what the traits actually mean here.

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.