Sending type that is !Send

Hi guys,
How to send a type, that is not send? I've tried:
Arc<RwLock>//no go
Arc<Mutex>//no go

Which surprised me a lot, as I thought that it is the way to send types that do not implement Send trait.

The whole point of !Send is that you can't send it to another thread. Being able to send an !Send type to another thread is unsound. For example:

let a = Rc::new(1);
let b = a.clone();
thread::spawn(|| {
    b.clone(); // This is UB if it were to compile as there is a data-race with the other thread when incrementing the reference count.
});
a.clone(); // This would data-race with the other thread when incrementing the reference count.

This code doesn't actually compile as Rc is !Send to prevent concurrent (non-atomic) accesses to the reference count.

It's possible with something like fragile, i.e. with something that prevents this type from actually being accessed after sending. It's unsound otherwise, no matter the wrapper used.

Arc and RwLock/Mutex are used for another case - to make Send + !Sync type effectively Sync, i.e. to share between threads something that can be sent.

5 Likes

Thanks for the suggestion and explanation.

Would that also imply that let's say type that has !Send insite it, like raw ptr is !Send itself, and type that as a members has all members that are Send is also Send itself?

Yes, that's how the automatic implementations are set up.

Depending on how they're being used, however, it is sometimes OK to send something like a raw pointer to another thread if you're also providing some other access control mechanism. For these cases, you can unsafe impl Send for MyTypeWhichContainsAPointer {}— It's then up to you to ensure that whatever you're doing with that pointer can't result in a data race, use after free, etc. when used in a multi-threaded way.

Thanks for confirmation.

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.