Issue
OB_HM is Arc<Mutex<HashMap<...>>>
This caused the deadlock at very first iteration:
let mut OB_HM__:HashMap<u8, (f64, f64, f64, f64)> = HashMap::new();
for i in &p {
OB_HM__.insert(
*i,
(
OB_HM.lock().unwrap()[i].0, OB_HM.lock().unwrap()[i].1
R[&i].0,
R[&i].1
)
);
};
let mut OB_HM = OB_HM__;
And this solved it:
let mut OB_HM__:HashMap<u8, (f64, f64, f64, f64)> = HashMap::new();
for i in &p {
let x = OB_HM.lock().unwrap()[i].0;
let y = OB_HM.lock().unwrap()[i].1;
OB_HM__.insert(
*i,
(
x, y,
R[&i].0,
R[&i].1
)
);
};
let mut OB_HM = OB_HM__;
Why so? I had mere intuition but I need to understand the internals behind it. I'm guessing it has to do with how Rust creates tuples or how the method insert works?
And a side question about insert - why does it require ; EOL when it's the only instruction inside a loop?
Solution
This caused the deadlock at very first iteration [...] Why so?
Shortly, because of temporary lifetime extension.
Generally1, OB_HM.lock() create a new object, a mutex guard.
This is a temporary object and it implements Deref trait (allowing autoderef).
De-referencing the mutex guard creates a borrow of the inner object (i.e., the HashMap) that extends the lifetime of the guard itself.
Therefore, the mutex guard is not dropped until the end of entire function call (i.e., insert) and so the Mutex is not unlocked. Since you have two locks in your function call expression, that generates a deadlock.
Maybe a toy-example might help to understand: example.
From the above,
foo(mutex.lock().value(), // <--- first lock
mutex.lock().value()); // <--- second lock
produces a deadlock because both locks are released only after the entire expression foo (the function call) has been evaluated.
Indeed the output:
MutexLock! // <--- First lock
MutexLock! // <--- Second lock
> !DEADLOCK! < // <--- Two interleaved locks! Deadlock!
foo: Call!
// <--- Now the function ends
MutexUnlock // <--- And only at the end the mutex are unlocked!
MutexUnlock
Note that, this is independent from tuples.
The "working" solution works because:
let x = OB_HM.lock().unwrap()[i].0;
let y = OB_HM.lock().unwrap()[i].1;
the temporary expression of lock lasts for the entire statement.
So after x has been assigned, the temporary lock is released. Allowing y to acquire it without deadlocks.
And a side question about insert - why does it require ; EOL
Because of rust syntax I guess.
From here: loop syntax
loop BlockExpression
where BlockExpression is defined as zero or more statements.
Expression are accepted only as expression-statements (that is, with ;).
- It might depend on your
Mutextype.
Answered By - BiagioF Answer Checked By - Terry (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.