Confusing automatic dereferencing of Arc

折月煮酒 提交于 2020-08-25 08:20:12

问题


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();
}   

回答1:


Follow the docs. Starting with Arc<T>:

  • Does Arc::lock exist? No. Check Deref.
  • Deref::Target is T. Check Mutex<T>.
  • Does Mutex::lock exist? Yes. It returns LockResult<MutexGuard<T>>.
  • Where does unwrap come from? LockResult<T> is a synonym for Result<T, PoisonError<T>>. So it's Result::unwrap, which results in a MutexGuard<T>.
  • Therefore, data is of type MutexGuard<usize>.

So this is wrong:

so when calling data.lock(), I assumed that the Arc is being automatically dereferenced and an usize is assigned to data.

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.
  • It says that for MutexGuard<T>, it implements DerefMut::deref_mut(&mut self) -> &mut T.
  • Thus, the result of *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.



来源:https://stackoverflow.com/questions/46314582/confusing-automatic-dereferencing-of-arc

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!