为什么“如果让我们”使用Mutex阻止执行?

Web*_*rix 8 concurrency mutex rust

我在工作时遇到了这种僵局 Mutex

包含Mutex类型字段的结构如下:

struct MyStruct {
    inner_map: Arc<Mutex<HashMap<i32, Vec<i32>>>>,
}
Run Code Online (Sandbox Code Playgroud)

我已经通过互斥锁访问了此内部地图:

impl MyStruct {
    fn test_lock(&self, key: &i32) {
        let my_option = self.inner_map.lock().unwrap().remove(key);
        if let Some(my_vec) = my_option {
            for _inner_val in my_vec {
                self.inner_map.lock().unwrap();
                println!("Passed test_lock1");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这没有死锁,可以正常工作,因为我从中删除了价值HashMap并获得了所有权HashMap


与test_lock非常相似的函数,仅具有区别,而不是my_option在动态if let调用中使用已声明的变量删除值,并且在这种情况下会导致死锁

impl MyStruct{
    // Why this function goes to deadlock since remove gets the ownership of the data?
    fn test_lock2(&self, key: &i32) {
        if let Some(my_vec) = self.inner_map.lock().unwrap().remove(key) {
            for _inner_val in my_vec {
                self.inner_map.lock().unwrap();
                println!("Passed test_lock2");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

声明变量会改变这种行为的主要原因是什么?

操场

Den*_*ret 8

LockResult超出范围时,将释放锁定

现在,我们必须对有关此临时值的范围规则进行更深入的研究。

临时值的范围是封闭语句。

在第一个代码段中,这意味着锁在进入if / let构造之前超出范围。没有僵局。

但是if let条件中临时值的范围是整个if / let构造:

临时值的寿命通常是

  • 最内在的陈述;块的尾部表达式被视为包围该块的语句的一部分,或者
  • 条件表达式或循环条件表达式(如果在if或while表达式的循环条件表达式中创建了临时项)

但是,当创建分配给let声明的临时值表达式时,将使用封闭块的生存期来创建该临时值,因为使用封闭的let声明将确保出现错误(因为指向临时块的指针会被存储到变量中,但在使用该变量之前将释放临时变量)

在第二个片段中,锁的范围因此覆盖了整个if / let构造。

这解释了为什么当您尝试再次在循环中锁定时,第一个锁定仍处于活动状态。