Ch 31: std::sync::RwLock - 读写锁
std::sync::RwLock(读写锁)允许多个读线程同时访问,但写操作需要独占访问。相比Mutex,在读多写少的场景下性能更好。
2. 基本用法
Section titled “2. 基本用法”use std::sync::RwLock;
fn main() { let lock = RwLock::new(5i32);
// 读操作 - 可以多个同时进行 { let r1 = lock.read().unwrap(); let r2 = lock.read().unwrap(); println!("读锁1: {}, 读锁2: {}", *r1, *r2); }
// 写操作 - 独占访问 { let mut w = lock.write().unwrap(); *w = 10; println!("写入: {}", *w); }
println!("最终值: {}", *lock.read().unwrap());}3. 方法签名
Section titled “3. 方法签名”impl<T> RwLock<T> { pub fn new(t: T) -> RwLock<T>
// 读锁 pub fn read(&self) -> Result<RwLockReadGuard<T>, PoisonError<RwLockReadGuard<T>>> pub fn try_read(&self) -> Result<RwLockReadGuard<T>, TryLockError>
// 写锁 pub fn write(&self) -> Result<RwLockWriteGuard<T>, PoisonError<RwLockWriteGuard<T>>> pub fn try_write(&self) -> Result<RwLockWriteGuard<T>, TryLockError>
// 其他 pub fn is_poisoned(&self) -> bool pub fn read_timeout(&self, timeout: Duration) -> Result<RwLockReadGuard<T>, PoisonError<RwLockReadGuard<T>>> pub fn write_timeout(&self, timeout: Duration) -> Result<RwLockWriteGuard<T>, PoisonError<RwLockWriteGuard<T>>>}4. try_read / try_write - 非阻塞获取
Section titled “4. try_read / try_write - 非阻塞获取”use std::sync::RwLock;use std::thread;
fn main() { let lock = RwLock::new(0i32);
// 立即获取读锁 if let Ok(_guard) = lock.try_read() { println!("立即获取读锁成功"); }
// 获取写锁 let _write_guard = lock.write().unwrap();
// 尝试获取读锁会失败(因为有写锁持有者) match lock.try_read() { Ok(_) => println!("获取读锁成功"), Err(_) => println!("获取读锁失败,写锁被占用"), }
// 尝试获取写锁也会失败 match lock.try_write() { Ok(_) => println!("获取写锁成功"), Err(_) => println!("获取写锁失败"), }}5. RwLockReadGuard / RwLockWriteGuard
Section titled “5. RwLockReadGuard / RwLockWriteGuard”use std::sync::RwLock;use std::sync::RwLockReadGuard;
fn main() { let lock = RwLock::new(vec![1, 2, 3]);
// 读Guard let guard: RwLockReadGuard<Vec<i32>> = lock.read().unwrap(); println!("长度: {}", guard.len()); // guard隐式drop释放读锁}6. 与Mutex对比
Section titled “6. 与Mutex对比”use std::sync::{Mutex, RwLock};use std::thread;
fn main() { // Mutex:同时只有一个线程能访问 let m = Mutex::new(0i32);
// RwLock:多个读或一个写 let r = RwLock::new(0i32);
let m_handles: Vec<_> = (0..100).map(|_| { let m = Arc::clone(&m); thread::spawn(move || { let mut g = m.lock().unwrap(); *g += 1; }) }).collect();
let r_handles: Vec<_> = (0..100).map(|_| { let r = Arc::clone(&r); thread::spawn(move || { let mut g = r.write().unwrap(); *g += 1; }) }).collect();
// RwLock在读多写少时更高效}7. 实际应用场景
Section titled “7. 实际应用场景”use std::sync::RwLock;use std::collections::HashMap;
struct Cache { data: RwLock<HashMap<String, String>>,}
impl Cache { fn new() -> Self { Cache { data: RwLock::new(HashMap::new()), } }
fn get(&self, key: &str) -> Option<String> { let guard = self.data.read().unwrap(); guard.get(key).cloned() }
fn insert(&self, key: String, value: String) { let mut guard = self.data.write().unwrap(); guard.insert(key, value); }
fn clear(&self) { let mut guard = self.data.write().unwrap(); guard.clear(); }}
fn main() { let cache = Cache::new(); cache.insert("key1".to_string(), "value1".to_string()); println!("获取: {:?}", cache.get("key1"));}8. 注意事项
Section titled “8. 注意事项”- 读多写少:RwLock在读操作多于写操作时优势明显
- 锁升级:不支持从读锁升级到写锁(可能死锁)
- PoisonError:与Mutex一样支持中毒机制
- 性能开销:相比Mutex有稍大的开销
- 死锁:与Mutex类似,避免嵌套写锁
std::sync::RwLock核心API:
read()- 获取读锁(阻塞)try_read()- 尝试获取读锁(非阻塞)write()- 获取写锁(阻塞)try_write()- 尝试获取写锁(非阻塞)RwLockReadGuard/RwLockWriteGuard- 守卫类型
选择建议:
- 读多写少:RwLock
- 写多读少:Mutex
- 需要更简单语义:Mutex