🦍
Mutexは if let ... else ブロックに渡って保持される話
Mutex
はif let ... else
ブロックに渡って保持される話
Twitterで次の記事が流れてきて、所見でなにも分からなかったので調べてみました。
記事のおさらい
上記の記事を読めば分かると思いますが、一応簡潔に説明します。
2つのスレッドからcounter
にアクセスする際にロックを取得するが、if let { ... } else { ... }
を抜けるまで、別スレッドで取得したロックが開放されない
if let Some(_) = counter.lock().unwrap().checked_div(i) { // lock scope +
// |
} else { // |
thread::sleep(time::Duration::from_millis(100)); // |
} // -----------+
しかし、通常のif { ... } else { ... }
だと、想定とおりif
ブロックを抜けた時点でロックが開放される挙動をしている
if counter.lock().unwrap().checked_div(i).is_some() { // lock scope +
// |
} else { // -----------+
thread::sleep(time::Duration::from_millis(100));
}
というお話です。
if let ... else
はmatch
のシンタックスシュガー
if let
構文は、match
のシンタックスシュガーと考えることができます。[1]
そのため、デシュガーすると次のようになります。
if let Some(_) = counter.lock().unwrap().checked_div(i) {
} else {
thread::sleep(time::Duration::from_millis(100));
}
// デシュガー後
let counter = counter.lock().unwrap().checked_div(i); // lock scope +
match counter { // |
Some(_) => {} // |
None => { // |
thread::sleep(time::Duration::from_millis(100)); // |
} // |
}; // -----------+
このようにデシュガーするとわかりますが、ロックはmatch式が終わるまで保持します。
また、Clippy先生の方でも「The Mutex lock remains held for the whole if let ... else block and deadlocks.」と書いてあります。
最後
Rustむずい
参考文献
- https://rust-lang.github.io/rust-clippy/master/index.html#/if_let_mutex
- https://doc.rust-lang.org/book/ch06-03-if-let.html
- https://github.com/rust-lang/rust/issues/28449
- https://qiita.com/0yoyoyo/items/7410b6897a4a202db67d#:~:text=syntax sugarをdesugarする。forやif letなどはmatchを用いた表現のsyntax sugarとなっているため
Discussion
拙文を読んでいただきありがとうございました。
Rust難しいですね
でも、Rustでネットワークプログラミングするのは楽しいです!