使用Arc和Mutex时Rust线程间共享状态更新失效问题排查
问题分析
你的问题核心在于**stdout锁的持有时间过长**,导致两个线程的执行互相阻塞:
handle_client线程在整个输入循环开始时就获取了stdout的锁,并且在循环全程持有该锁未释放。do_broadcast线程每次循环都需要获取stdout锁才能执行broadcast,但由于handle_client一直持有锁,do_broadcast会被持续阻塞,直到handle_client退出循环、释放锁后才能执行一次broadcast——这就是只有handle_client退出时才能看到更新的原因。
修复方案
调整handle_client线程中stdout锁的获取时机,将其从循环外移到循环内部,每次处理单个输入时临时获取锁,处理完成后自动释放:
let handle_client = thread::spawn(move || { let stdin = io::stdin().lock(); let inputs = serde_json::Deserializer::from_reader(stdin).into_iter::<Message<Payload>>(); for input in inputs { thread::sleep(Duration::from_millis(1)); let input = input.context("cannot deserialize the input message").unwrap(); // 每次处理输入时才获取stdout锁,执行完step后自动释放 let mut stdout = io::stdout().lock(); _node.lock().unwrap().step(input, &mut stdout).unwrap(); } });
同时建议调整do_broadcast线程的锁获取顺序,先获取Node的锁再获取stdout锁,统一锁的获取顺序能避免潜在的死锁风险:
let do_broadcast = thread::spawn(move || loop { // 先获取Node锁,再获取stdout锁 let mut node_guard = _node.lock().unwrap(); let mut stdout = io::stdout().lock(); node_guard.broadcast(&mut stdout); // 离开当前作用域后,两个锁会自动释放 thread::sleep(Duration::from_millis(100)); });
额外优化建议
- 避免在持有锁的状态下执行长时间操作,当前代码中的
sleep都在锁释放后执行,这点符合最佳实践。 - 生产环境中建议替换
unwrap(),改用match或if let做更优雅的错误处理,避免因锁获取失败、反序列化失败等情况直接导致程序panic。
内容的提问来源于stack exchange,提问作者Harsh Kumar Chourasia
相关产品推荐
相关产品推荐

