You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust线程并行与共享资源更新疑问:Mutex为何未按预期解锁?

为什么Rust中Mutex保护的线程会连续执行完所有迭代?

你的代码核心问题是Mutex锁的作用域过大。每个线程的循环中,lock()返回的MutexGuard(也就是代码里的num)作用域覆盖了整个循环体——从获取锁开始,到sleep、println执行完毕,num才会离开作用域,Mutex才会被解锁。

这意味着线程拿到锁后,会持有它整整一次迭代的时间:包括修改计数器、sleep 10毫秒、打印内容。在sleep的10毫秒里,锁依然被当前线程攥着,其他线程完全无法获取Mutex,只能原地等待。而当前线程解锁后,会立刻进入下一次循环再次抢锁——操作系统通常会优先调度刚刚释放锁的线程,所以它能反复抢到锁,直到跑完所有5次迭代,才会轮到其他线程执行。

修复方案:缩小锁的作用域

把锁的持有范围严格限制在仅修改计数器的阶段,修改完成后立刻释放锁,让其他线程有机会获取锁。

优化后的代码(保存修改后的值避免重复加锁)

use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

fn main() {
    let counter = Arc::new(Mutex::new(0));

    let counter_clone1 = Arc::clone(&counter);
    let t1 = thread::spawn(move || {
        for _ in 0..5 {
            // 仅在修改计数器时持有锁,修改完成后立即释放
            let current_val = {
                let mut num = counter_clone1.lock().unwrap();
                *num += 1;
                *num // 返回当前值,代码块结束后num被drop,Mutex解锁
            };
            thread::sleep(Duration::from_millis(10));
            println!("printing from the thread 1 value --> {}", current_val);
        }
    });

    let counter_clone2 = Arc::clone(&counter);
    let t2 = thread::spawn(move || {
        for _ in 0..5 {
            let current_val = {
                let mut num = counter_clone2.lock().unwrap();
                *num += 1;
                *num
            };
            thread::sleep(Duration::from_millis(10));
            println!("printing from the thread 2 value --> {}", current_val);
        }
    });

    let counter_clone3 = Arc::clone(&counter);
    let t3 = thread::spawn(move || {
        for _ in 0..5 {
            let current_val = {
                let mut num = counter_clone3.lock().unwrap();
                *num += 1;
                *num
            };
            thread::sleep(Duration::from_millis(10));
            println!("printing from the thread 3 value --> {}", current_val);
        }
    });

    t1.join().unwrap();
    t2.join().unwrap();
    t3.join().unwrap();

    println!("final value of counter --> {}", counter.lock().unwrap());
}

修改后,每个线程修改完计数器就立刻释放锁,sleep和打印时锁处于自由状态,其他线程可以随时获取锁修改计数器,就能得到你预期的线程交替执行的输出效果。

内容的提问来源于stack exchange,提问作者Soumyajit Roy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 21:35:18