面试题答案
一键面试- 使用Mutex保护共享数据
- 定义Mutex包裹共享数据:
use std::sync::{Arc, Mutex}; // 定义复杂数据结构 struct Inner { value: i32, // 可以有更多嵌套结构体等 } struct Outer { inner: Inner, // 其他成员 } let shared_data = Arc::new(Mutex::new(Outer { inner: Inner { value: 0 }, }));
- 线程中访问共享数据:
let data_clone = shared_data.clone(); std::thread::spawn(move || { let mut data = data_clone.lock().unwrap(); data.inner.value += 1; });
- 在每个线程中,通过
lock
方法获取Mutex的锁。如果锁可用,lock
会返回一个MutexGuard
,它实现了Deref
和DerefMut
,所以可以像操作普通数据一样操作共享数据。在MutexGuard
离开作用域时,锁会自动释放。
- 定义Mutex包裹共享数据:
- 可能遇到的问题及解决方案
- 死锁:
- 问题描述:如果多个线程互相等待对方持有的锁,就会发生死锁。例如,线程A持有锁1并等待锁2,而线程B持有锁2并等待锁1。
- 解决方案:
- 尽量减少锁的持有时间,在获取锁后尽快完成必要操作并释放锁。
- 采用固定的锁获取顺序,所有线程都按照相同顺序获取多个锁,避免循环依赖。
- 性能问题:
- 问题描述:如果锁的粒度太粗,所有线程频繁竞争同一把锁,会导致性能瓶颈,因为同一时间只有一个线程能访问共享数据。
- 解决方案:
- 细分锁,将共享数据按照功能或访问模式分成不同部分,每个部分使用不同的Mutex保护。这样不同线程可以同时访问不同部分的数据。
- 使用读写锁(
RwLock
),如果读操作远多于写操作,可以使用RwLock
。读操作可以同时进行,只有写操作需要独占锁,从而提高并发性能。
- MutexGuard生命周期问题:
- 问题描述:如果不小心延长了
MutexGuard
的生命周期,可能会导致其他线程长时间无法获取锁。例如,将MutexGuard
存储在一个长生命周期的变量中。 - 解决方案:确保
MutexGuard
只在需要的最小作用域内存在,及时释放锁。不要将MutexGuard
存储在不必要的长生命周期数据结构中。
- 问题描述:如果不小心延长了
- 死锁: