2026-09-14
drain_queue.rs
use std::sync::Mutex;
fn drain(queue: &Mutex<Vec<u32>>) {
while let Some(job) = queue.lock().unwrap().pop() {
if job > 1 {
queue.lock().unwrap().push(job - 1);
}
}
}
キューが空になるまでジョブを取り出して処理する関数です。1より大きいジョブが出てくると、そこで止まって戻ってきません。何が問題で、どう直せばよいでしょうか?
Answer
while letの条件式で作られた一時値は、条件の評価が終わっても破棄されず、その周のループ本体が終わるまで生き続けます。そのためlock()が返したMutexGuardもロックを握ったままで、本体でもう一度lock()すると戻ってきません(std::sync::Mutexを同じスレッドで再ロックすると、デッドロックかパニックになります)。取り出しを独立したlet文に分ければ、ガードはその文の終わりで破棄されます:
loop {
let Some(job) = queue.lock().unwrap().pop() else { break };
if job > 1 {
queue.lock().unwrap().push(job - 1);
}
}