This is an example taken from the Mutex
documentation:
use std::sync::{Arc, Mutex};
use std::sync::mpsc::channel;
use std::thread;
const N: usize = 10;
fn main() {
let data = Arc::new(Mutex::new(0));
let (tx,rx) = channel();
for _ in 0..N{
let (data, tx) = (data.clone(), tx.clone());
thread::spawn(move || {
// snippet
});
}
rx.recv().unwrap();
}
My question is where the snippet
comment is. It is given as
let mut data = data.lock().unwrap();
*data += 1;
if *data == N {
tx.send(()).unwrap();
}
The type of data is Arc<Mutex<usize>>
, so when calling data.lock()
, I assumed that the Arc
is being automatically dereferenced and an usize
is assigned to data
. Why do we need a *
in front of data
again to dereference it?
The following code which first dereferences the Arc
and then proceeds with just an usize
also works in place of the snippet.
let mut data = *data.lock().unwrap();
data += 1;
if data == N {
tx.send(()).unwrap();
}
Follow the docs. Starting with Arc<T>
:
Arc::lock
exist? No. Check Deref
.Deref::Target
is T
. Check Mutex<T>
.Mutex::lock
exist? Yes. It returns LockResult<MutexGuard<T>>
.unwrap
come from? LockResult<T>
is a synonym for Result<T, PoisonError<T>>
. So it's Result::unwrap
, which results in a MutexGuard<T>
.data
is of type MutexGuard<usize>
.So this is wrong:
so when calling
data.lock()
, I assumed that theArc
is being automatically dereferenced and anusize
is assigned todata
.
Thus the question is not why you can't assign directly, but how you're able to assign an usize
value at all. Again, follow the docs:
data
is a MutexGuard<usize>
, so check MutexGuard<T>
.*data
is a pointer dereference in a context that requires mutation. Look for an implementation of DerefMut
.MutexGuard<T>
, it implements DerefMut::deref_mut(&mut self) -> &mut T
.*data
is &mut usize
.Then we have your modified example. At this point, it should be clear that this is not at all doing the same thing: it's mutating a local variable that happens to contain the same value as the mutex. But because it's a local variable, changing it has absolutely no bearing on the contents of the mutex.
Thus, the short version is: the result of locking a mutex is a "smart pointer" wrapping the actual value, not the value itself. Thus you have to dereference it to access the value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With