`Mutex<&T>` misses `Sync` and `Send` trait implementations when `T` isn't `Send`

Mutex<&T> misses Sync and Send trait mplementations when T isn't Send.

Please add

unsafe impl<'mutex, T: ?Sized + Sync> Sync for Mutex<'mutex, T> {}
unsafe impl<'mutex, T: ?Sized> Send for Mutex<'mutex, T> { }

to struct Mutex.

I've a few minutes ago uploaded a workaround:

This library implement RefMutex<T> that is similar to Mutex<T> but is Sync and Send even if T isn't Send.

I did it correctly, didn't I?

Please try not to keep suggesting supposedly missing, but actually unsound capabilities of Mutex to the standard library.

For review of your own crates, or if you're just wondering why the Sync implementation is the way it is or why Mutex is not covariant, consider asking a question on users.rust-lang.org.

8 Likes

I searched for existing explanations, this post seems decent. Hope it helps

Wait.. you're saying Mutex<&T>, not Mutex<T>. The type Mutex<&T> shouldn't be requiring T: Send at all already – just T: Sync – but the T: Sync bound is required for both Mutex<&T>: Send as well as Mutex<&T>: Sync.

Thank you for your reference. But the conclusion seems to be the opposite: Mutex<&T> is UnsaveCell<&T> in disguise, and UnsaveCell<&T> is &&T in disguise. So, accordingly to the document you linked to, Mutex<&T> should be Send indeed, so I seem to be correct.

You are correct but Mutex<&T> is not Send, and I think it should be Send.

So, my idea seems valid. Or do I have any other mistakes?

no, UnsafeCell it's not a reference type.

It already is Send if T: Sync, and it shouldn't be in any other case.

T: Sync is required for sending &T between threads, and you could wrap that in a mutex, send it and into_inner it back into the &T, so you also need the T: Sync bound in order to send a Mutex<&T>

1 Like

@steffahn

You are right, I have an error: &T may be "equal" to some mutable reference and it breaks sychronization.

So, to make my code work, we need to ensure that the passed &T is the only reference to our object (of type T) or at least there are no &mut references to it. The only way I know to do this, is to wrap &T inside an unsafe Sync struct with &T as a private field. This unsafe Sync struct cannot be implemented in a "general" way, because generally &T can be return value of a function and nothing prevent a function to make also &mut references. Therefore the unsafe Send struct needs to be implemented every time anew. Too bad.

If there is no any other way, the following new Rust feature would be useful: Make &T: Send while there are no known mutable references. Adding this feature would solve my Mutex troubles automatically.

(Sorry for polluting this group with a relatively novice's ideas, but not to respond to your message is also not good.)

Oh, it can be done on library level:

struct SendableRef<'a, T> {
    base: &'a T,
}

impl SendableRef {
    pub fn new(obj: T) {
        &obj
    }
    pub fn to_ref(&self) {
        self.base
    }
}

unsafe impl Send for SendableRef<'_, '_> {}

impl Deref for SendableRef<'_, '_> {
    ...
}

...

Is there such a type in some library or me to implement it?

Oh, it is already done: send_cell - Rust

1 Like

No problem, I was mostly concerned about future topics, not knowing at what rate you were planning to post further ideas that are mostly questions for help in disguise (help with understanding technical details); when it's already open, we may as well keep using this thread. Also on users.rust-lang.org there tend to be more people willing to answer (novice) questions so you might get answers faster and/or better answers.

Feel free to still open topics for ideas on internals.rust-lang.org whenever you do think understand the details a bit better, or e. g. if other Rust users on users.rust-lang.org already confirmed the idea could make sense.

2 Likes

Tip: while you are a newcomer to Rust, it's safer to assume that the authors of the standard library know its internal workings better than you do, and that functionality is not "missing", it is rather left out intentionally.

Unsafe code is specifically hard to reason about unless you are really experienced. Unless you have at least an informal proof of the soundness of your proposal, you should just probably not post it at all. I.e., if you need to ask if it is sound, it usually isn't. (The same goes for compiler bugs.)

5 Likes

Please note that this example code isn't sound, since it allows getting multiple. references from different threads to T even if it doesn't implement Sync.

send_cell is sound, since it only allows the thread that created the type to access it.

2 Likes