如何在使用防护时避免互斥借用问题

Vic*_*voy 1 mutex rust

我希望我的struct方法以同步方式执行.我想通过使用Mutex(游乐场)来做到这一点:

use std::sync::Mutex;
use std::collections::BTreeMap;

pub struct A {
    map: BTreeMap<String, String>,
    mutex: Mutex<()>,
}

impl A {
    pub fn new() -> A {
        A {
            map: BTreeMap::new(),
            mutex: Mutex::new(()),
        }
    }
}

impl A {
    fn synchronized_call(&mut self) {
        let mutex_guard_res = self.mutex.try_lock();
        if mutex_guard_res.is_err() {
            return
        }
        let mut _mutex_guard = mutex_guard_res.unwrap(); // safe because of check above
        let mut lambda = |text: String| {
            let _ = self.map.insert("hello".to_owned(),
                                    "d".to_owned());
        };
        lambda("dd".to_owned());
    }
}    
Run Code Online (Sandbox Code Playgroud)

错误信息:

error[E0500]: closure requires unique access to `self` but `self.mutex` is already borrowed
  --> <anon>:23:26
   |
18 |         let mutex_guard_res = self.mutex.try_lock();
   |                               ---------- borrow occurs here
...
23 |         let mut lambda = |text: String| {
   |                          ^^^^^^^^^^^^^^ closure construction occurs here
24 |             if let Some(m) = self.map.get(&text) {
   |                              ---- borrow occurs due to use of `self` in closure
...
31 |     }
   |     - borrow ends here
Run Code Online (Sandbox Code Playgroud)

据我所知,当我们从结构中借用任何东西时,我们无法使用其他结构的字段,直到我们的借用完成.但是我怎样才能进行方法同步呢?

Luk*_*odt 6

闭包需要一个可变的引用self.map,以便在其中插入一些东西.但是闭包捕获仅适用于整个绑定.这意味着,如果你说self.map,关闭尝试捕获self,而不是self.map.并且self不能被可变地借用/捕获,因为部分self已经不可避免地被借用了.

我们可以通过单独为地图引入一个新的绑定来解决这个闭包捕获问题,这样闭包就能捕获它(Playground):

let mm = &mut self.map;
let mut lambda = |text: String| {
    let _ = mm.insert("hello".to_owned(), text);
};
lambda("dd".to_owned());
Run Code Online (Sandbox Code Playgroud)

但是,有些事情你忽略了:既然synchronized_call()接受了&mut self,你就不需要互斥体了!为什么?可变引用也称为独占引用,因为编译器可以在编译时确保在任何给定时间只有一个这样的可变引用.

因此,您静态地知道,如果函数不是递归的synchronized_call(),在任何给定时间最多只有一个实例在一个特定对象上运行(调用自身).

如果您具有对互斥锁的可变访问权限,则表示该互斥锁已解锁.见Mutex::get_mut()更多的解释方法.这不是很棒吗?