The cool bit is that get_mut on Mutex gives access without locking it and it’s perfectly safe, because you can do that only when the borrow checker has proven you have exclusive access.
Does this apply to any situations other than “I’ve just created the mutex and haven’t passed it to anywhere else yet”?
This, plus “I’ve collected results from all the threads and now put them together”.
This would require an Arc and Arc::get_mut in the multithreaded context, no?
Usually yes, and you can similarly unwrap them when the refcount is 1.
There are also scoped threads that’d allow &Mutex.
I get the argument that using an encapsulating mutex is safer for guarding against mutations on a reference, I think the author misses one separate situation where that api is awkward, specifically if the critical section spans individual mutations. For that you will want a whole grain lock/unlock pattern, and specifically something like go’s defer keyword to be confident you’ll safely release regardless of what happens.
People reading this are misunderstanding what I mean by “awkward”; what I mean here is that there is another field you have to add as the syncroot for the mutex, in addition to the mutex, if you’re guarding something that isn’t strictly mutating a single field.
I may be misunderstanding, but the Rust API supports that — you acquire the guard object, make multiple changes to the data through it, and the mutex is automatically unlocked when it goes out of scope.
I’ve implemented this same design in C++ and it works very well. It’s safe, efficient, and very easy to use. (In C++ the trick is to explicitly delete the copy and move operations on the guard object that’s returned from the lock call, so there’s no way to extend its lifespan.)
Can you provide an example of such code? Because I cannot think about a case when Rust design would lack anything (and MutexGuard is exactly the same as Go’s defer just without need for developer to write it explicitly).