3 ms·
>> With a normal mutex we would be fine, since you only one lock can exist and it doesn’t matter if we unlock it on a thread other than the one we locked it fro
by applesvsoranges 8y ago
>> With a normal mutex we would be fine, since you only one lock can exist and it doesn’t matter if we unlock it on a thread other than the one we locked it from.
Sorry if this is a dumb question, but I'm confused. Aren't mutexes always supposed to have ownership which implies that only the locking thread can unlock them?
- dfox 8y agoIn almost any implementation you don't want to track the owner because it is only an unnecessary overhead and nothing else. On a similar note the articles strikes me as somewhat contrived example, because the most obvious implementation of reentrant mutex also does not care about the owner thread. Edit: Another reason why it feel contrived is that in fact reentrant mutex represented as first class datastructure (in contrast to monitor as an language-level construct) is to some extent only an hack to solve issues stemming from improper design.
- amaranth 8y agoA reentrant mutex will allow you to unlock it multiple times so long as you're on the same thread. That means if Thread A takes the lock then later some code on Thread A tries to take the lock again to get a connection to pass to Thread B you'll have the connection the mutex was protecting on two threads at the same time. The rust version of the mutex prevents this by making the data the mutex is protecting unable to be sent to other threads. That means you can only share the mutex which will block on Thread B when you try to take the lock, as expected.
- scottlamb 8y ago> Sorry if this is a dumb question, but I'm confused. Aren't mutexes always supposed to have ownership which implies that only the locking thread can unlock them? Mutexes are supposed to ensure that exactly one thread can accesses resource ("have the lock") at a time. There's no fundamental reason you can't pass the lock from one thread to another, as long as they don't both have it at once. But it may not be supported by the particular mutex implementation. It's not supported by the recursive mutexes the author was using, and I'd bet there are also non-recursive mutex implementations which don't support it. I agree with the author that it's great Rust can catch this sort of mistake. btw, I think recursive mutexes and handing off locks are bad ideas. Both for the same reason: I want short critical sections to improve contention. * Code that uses recursive mutexes tends to be sloppy about this; it's unclear from reading a section of code whether it even has the lock or not. (This also sounds like a recipe for deadlock when you need multiple locks.) I'd much rather structure it so a given piece of code is run only with or without the lock. In C++, I use lock annotations [1] for this. If I need something to be callable with or without the lock, I might have a private "DoThingLocked()" bit, and a public "DoThing()" bit that delegates while holding the lock. This should also be more efficient (though maybe it's insignificant) because there's no run-time bookkeeping for the recursive mutex. * Handing off the mutex to another thread also feels like a smell that you're holding the lock longer than you need. I don't recall a time I've ever needed to do it. From the description here, it seems totally reasonable to hold a mutex while getting a connection from the pool and while returning one to it, but not between. I'd think you could get the connection, then create the new thread (passing the connection to it). [1] https://clang.llvm.org/docs/ThreadSafetyAnalysis.html https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
- applesvsoranges 8y agoThanks, this adds a whole new perspective for me wrt mutexes. I wasn't aware of all these other usage patterns for them at all. Most of my work is in the OS, drivers and low level space, and I'm a beginner there as well, hence the short critical sections under a single owner are the only places I had encountered them before.