令人困惑的Arc自动解除引用

时间:2017-09-20 06:16:30

标签: rust

这是取自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();
}

我的问题是snippet评论的位置。它以

给出
let mut data = data.lock().unwrap();
*data += 1;
if *data == N {
    tx.send(()).unwrap();
}

数据类型为Arc<Mutex<usize>>,因此在调用data.lock()时,我认为Arc被自动解除引用,而usize被分配给data }。为什么我们需要再次在*前面data取消引用它?

以下代码首先取消引用Arc,然后仅使用usize,也可以代替代码段。

let mut data = *data.lock().unwrap();
data += 1;
if data == N {
    tx.send(()).unwrap();
}   

1 个答案:

答案 0 :(得分:10)

关注文档。从Arc<T>开始:

  • Arc::lock是否存在?不。检查Deref
  • Deref::TargetT。检查Mutex<T>
  • Mutex::lock是否存在? Yes。它返回LockResult<MutexGuard<T>>
  • unwrap来自哪里? LockResult<T>Result<T, PoisonError<T>>的同义词。所以它是Result::unwrap,结果是MutexGuard<T>
  • 因此,data的类型为MutexGuard<usize>

所以这是错误的:

  

因此,在致电data.lock()时,我认为Arc被自动解除引用,而usize被分配给data

因此,问题不在于您无法直接分配,而是如何在所有分配usize。再次,按照文档:

  • dataMutexGuard<usize>,因此请检查MutexGuard<T>
  • *data是需要变异的上下文中的指针解除引用。寻找DerefMut
  • 的实现
  • 它表示对于MutexGuard<T>,它实现了DerefMut::deref_mut(&mut self) -> &mut T
  • 因此,*data的结果为&mut usize

然后我们有你修改过的例子。在这一点上,应该很清楚,完全没有做同样的事情:它正在改变一个碰巧包含与互斥锁相同值的局部变量。但因为它是局部变量,所以更改它绝对不会影响互斥锁的内容。

因此,短版本是:锁定互斥锁的结果是包装实际值的“智能指针”,而不是值本身。因此,您必须取消引用它才能访问该值。