Namaran

Code daily. Without assist.

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