【问题标题】:Why does 'if let' block the execution with usage of Mutex?为什么'if let'会阻止使用互斥锁的执行?
【发布时间】:2019-06-20 08:18:26
【问题描述】:

我在使用 Mutex 时遇到了这种死锁情况

包含Mutex类型字段的struct如下:

struct MyStruct {
    inner_map: Arc<Mutex<HashMap<i32, Vec<i32>>>>,
}

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

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

由于我从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");
            }
        }
    }
}

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

Playground

【问题讨论】:

  • 我怀疑即使在您的第一个非死锁代码中,您也会做一些本质上不安全的事情。没有真实的代码很难说,但是您确定不应该只为测试和条件为真时执行的操作设置一个锁吗?

标签: concurrency rust mutex


【解决方案1】:

The lock is released when the LockResult goes out of scope.

现在我们必须深入了解scope rules regarding this temporary value

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

在第一个 sn-p 中,这意味着锁在进入 if/let 构造之前超出了范围。没有死锁。

但是if let条件中临时值的作用域是整个if/let构造:

临时值的生命周期通常是

  • 最里面的封闭语句;块的尾部表达式是 被认为是包含块的语句的一部分,或
  • 条件表达式或循环条件表达式如果 在 if 的条件表达式中或在 while 表达式的循环条件表达式。

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

在第二个 sn-p 中,锁的作用域因此覆盖了整个 if/let 结构。

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

【讨论】:

  • 之前编写规范的方式,明确提到了 if/let,更加清晰。现在这感觉有点模棱两可......
  • 我刚刚被 RefCell 的这种行为所困扰。 if let Some(_) = cell.borrow().compute_stuff() { cell.borrow_mut().boom(); }: 没有借,所以我认为它会很好,但是跨越整个if 的守卫迫使我先计算然后匹配:)
猜你喜欢
  • 2016-10-25
  • 1970-01-01
  • 1970-01-01
  • 2021-02-27
  • 1970-01-01
  • 2010-11-18
  • 2014-02-28
  • 2011-02-28
  • 1970-01-01
相关资源
最近更新 更多