Почему «if let» блокирует выполнение с использованием Mutex? - PullRequest
8 голосов
/ 20 июня 2019

Я столкнулся с этим тупиковым сценарием при работе с Mutex

Структура, которая содержит поле типа Mutex, выглядит следующим образом:

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

Я получил доступ к этой внутренней карте через замок на Mutex:

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 переменная использовала его на лету * вызов 1017 * и в этом случае вызывает тупик :

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

Какова основная причина, по которой объявление переменной меняет такое поведение?

Детская площадка

1 Ответ

8 голосов
/ 20 июня 2019

Блокировка снимается, когда LockResult выходит из области действия .

Теперь мы должны углубиться в правила области действия относительно этого временного значения .

Область временного значения - это оператор вложения.

В первом фрагменте это означает, что блокировка выходит из области действия перед входом в конструкцию if / let.Нет тупика.

Но область действия временного значения в условии if let - это целая конструкция if / let:

время жизни временных значений обычно

  • самое внутреннее вложение заявления;хвостовое выражение блока считается частью оператора, который включает в себя блок, или
  • условного выражения или условного выражения цикла , если временное выражение создается в условном выражении if или в условном выражении цикла выражения while.

Когда создается временное выражение значения, которое назначается в объявлении let, однако временное создается с временем жизни включающего блока., так как использование декларации let является гарантированной ошибкой (поскольку указатель на временное хранилище будет сохранен в переменной, но временное будет освобождено до того, как переменная может быть использована)

Вво втором фрагменте область действия блокировки охватывает всю конструкцию if / let.

Это объясняет, почему первая блокировка все еще активна, когда вы пытаетесь снова заблокировать в цикле.

...