Rust 如何在使用互斥体时避免互斥体借用问题';卫兵

Rust 如何在使用互斥体时避免互斥体借用问题';卫兵,rust,mutex,Rust,Mutex,我希望我的struct方法以同步方式执行。我想通过使用Mutex()来实现这一点: 使用std::sync::Mutex; 使用std::collections::BTreeMap; 发布结构A{ 地图:BTreeMap, 互斥体:互斥体, } 暗示{ pub fn new()->A{ A{ 映射:BTreeMap::new(), 互斥体:互斥体::新建(()), } } } 暗示{ fn同步的_调用(&mut self){ 让mutex\u guard\u res=self.mutex.try

我希望我的struct方法以同步方式执行。我想通过使用
Mutex
()来实现这一点:

使用std::sync::Mutex;
使用std::collections::BTreeMap;
发布结构A{
地图:BTreeMap,
互斥体:互斥体,
}
暗示{
pub fn new()->A{
A{
映射:BTreeMap::new(),
互斥体:互斥体::新建(()),
}
}
}
暗示{
fn同步的_调用(&mut self){
让mutex\u guard\u res=self.mutex.try\u lock();
如果mutex\u guard\u res.是\u err(){
回来
}
让mut _mutex_guard=mutex_guard_res.unwrap();//由于上面的检查,所以是安全的
让mut lambda=| text:String |{
让u=self.map.insert(“hello.to_u-owned()”,
“d”。to_owned());
};
lambda(“dd.”to_owned());
}
}    
错误消息:

error[E0500]:闭包需要对'self'的唯一访问权限,但'self.mutex'已被借用
--> :23:26
|
18 |让mutex_guard_res=self.mutex.try_lock();
|-------借用发生在这里
...
23 |让mut lambda=| text:String |{
|^^^^^^^^^^^^^^^^^闭包构造发生在此处
24 |如果让一些(m)=self.map.get(&text){
|----借用是由于在闭包中使用“self”而产生的
...
31 |     }
|-借书到此为止

据我所知,当我们从结构中借用任何内容时,在借用完成之前,我们无法使用其他结构的字段。但是,我如何才能进行方法同步呢?

闭包需要对
self.map
的可变引用,以便插入某些内容。但是闭包捕获仅适用于整个绑定。这对我来说是一个问题答案是,如果你说
self.map
,闭包试图捕获
self
,而不是
self.map
。并且
self
不能被可变地借用/捕获,因为
self
的部分已经被不可变地借用

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


然而有一点您忽略了:由于
synchronized_call()
接受
&mut self
,您不需要互斥锁!为什么?可变引用也称为独占引用,因为编译器可以在编译时确保在任何给定时间只有一个这样的可变引用

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


如果您可以对互斥体进行可变访问,则知道互斥体已解锁。请参阅。这不是很神奇吗?

闭包需要对
self.map
的可变引用,以便在其中插入某些内容。但是闭包捕获仅适用于整个绑定。这意味着,如果您说
self.map
,闭包将尝试捕获ure
self
,而不是
self.map
。和
self
不能以可变方式借用/捕获,因为
self
的部分已被永久借用

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


然而有一点您忽略了:由于
synchronized_call()
接受
&mut self
,您不需要互斥锁!为什么?可变引用也称为独占引用,因为编译器可以在编译时确保在任何给定时间只有一个这样的可变引用

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


如果您可以对互斥体进行可变访问,则知道互斥体已解锁。请参阅。这不是很神奇吗?

Rust互斥体的工作方式与您尝试使用它们的方式不同。在Rust中,互斥体依靠语言中其他地方使用的借用检查机制来保护特定数据。因此,声明一个字段
互斥体
不会这是有意义的,因为它保护了对没有值可以改变的
()
单元对象的读写访问

正如Lukas解释的,声明的
调用\u synchronized
不需要进行同步,因为它的签名已经请求一个独占(可变)的对
self
的引用,这会阻止从同一对象上的多个线程调用它。换句话说,您需要更改
call\u synchronized
的签名,因为当前签名与它要提供的功能不匹配

call\u synchronized
需要接受对
self
的共享引用,这将首先向Rust发出信号,表明可以从多个线程调用它。在
call\u synchronized
内部,调用
Mutex::lock
将同时锁定互斥锁,并提供对底层数据的可变引用,注意完全限定范围,以便在引用期间保持锁定:

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

pub struct A {
    synced_map: Mutex<BTreeMap<String, String>>,
}

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

impl A {
    fn synchronized_call(&self) {
        let mut map = self.synced_map.lock().unwrap();
        // omitting the lambda for brevity, but it would also work
        // (as long as it refers to map rather than self.map)
        map.insert("hello".to_owned(), "d".to_owned());
    }
}
使用std::sync::Mutex;
使用std::collections::BTreeMap;
发布结构A{
同步映射:互斥体,
}
暗示{
pub fn new()->A{
A{
同步映射:Mutex::new(BTreeMap::new()),
}
}
}
暗示{
fn已同步的_调用(&self){
让mut map=self.synced_map.lock().unwrap();
//为简洁起见,省略lambda,但它也会起作用
//(只要它指的是地图而不是self.map)
map.insert(“hello.to_owned(),“d.to_owned());
}
}

Rust互斥锁的工作方式与您试图使用它们的方式不同。在Rust中,互斥锁可以保护
let mm = &mut self.map;
let mut lambda = |text: String| {
    let _ = mm.insert("hello".to_owned(), text);
};
lambda("dd".to_owned());
use std::sync::Mutex;
use std::collections::BTreeMap;

pub struct A {
    synced_map: Mutex<BTreeMap<String, String>>,
}

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

impl A {
    fn synchronized_call(&self) {
        let mut map = self.synced_map.lock().unwrap();
        // omitting the lambda for brevity, but it would also work
        // (as long as it refers to map rather than self.map)
        map.insert("hello".to_owned(), "d".to_owned());
    }
}