Вот MCVE для вашей проблемы:
use std::sync::Mutex;
fn main() {
let foo = Mutex::new(42i32);
let f1 = (*foo.lock().unwrap()).count_ones();
println!("f1: {}", f1);
let f2 = (*foo.lock().unwrap()).count_zeros();
println!("f2: {}", f2);
let tot = (*foo.lock().unwrap()).count_ones() + (*foo.lock().unwrap()).count_zeros();
println!("tot: {}", tot);
}
детская площадка
При запуске этого кода он напечатает f1
и f2
, затем зависнетпри попытке вычислить tot
.
Проблема в том, что Mutex::lock
возвращает MutexGuard
, который автоматически снимает блокировку, когда она выходит из области видимости.В приведенном выше примере охранники выходят из области видимости в конце выражений, в которых они используются.Поэтому, когда я пишу:
let f1 = (*foo.lock().unwrap()).count_ones();
, я получаю блокировку, считываю значение и освобождаю блокировку.Поэтому блокировка свободна при вычислении f2
.
Однако, когда я пишу:
let tot = (*foo.lock().unwrap()).count_ones() + (*foo.lock().unwrap()).count_zeros();
Я получаю блокировку, считываю значение, пытаюсь снова получить блокировку и только освобождаюоба охранника в конце линии.Это приводит к тому, что код блокируется, когда я пытаюсь получить блокировку во второй раз, не сняв ее сначала.
Обратите внимание, как прокомментировал trentcl, что ваш пример двух шагов зависит от условий гонки, если междудва раза мьютекс заблокирован.Вы должны использовать что-то вроде этого:
impl Node {
pub fn sign(&mut self) {
let protocol_handler = Arc::clone(&self.protocol);
self.thread_pool.execute(move || {
let handler = protocol_handler.lock().unwrap();
if !handler.is_leader && !handler.is_co_leader {
// Either this will be executed
}
// or this ...
})
}
}