Skip to content

Ch 31: std::sync::RwLock - 读写锁

std::sync::RwLock(读写锁)允许多个读线程同时访问,但写操作需要独占访问。相比Mutex,在读多写少的场景下性能更好。

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());
}
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>>>
}
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!("获取写锁失败"),
}
}
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释放读锁
}
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在读多写少时更高效
}
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"));
}
  1. 读多写少:RwLock在读操作多于写操作时优势明显
  2. 锁升级:不支持从读锁升级到写锁(可能死锁)
  3. PoisonError:与Mutex一样支持中毒机制
  4. 性能开销:相比Mutex有稍大的开销
  5. 死锁:与Mutex类似,避免嵌套写锁

std::sync::RwLock核心API:

  • read() - 获取读锁(阻塞)
  • try_read() - 尝试获取读锁(非阻塞)
  • write() - 获取写锁(阻塞)
  • try_write() - 尝试获取写锁(非阻塞)
  • RwLockReadGuard / RwLockWriteGuard - 守卫类型

选择建议:

  • 读多写少:RwLock
  • 写多读少:Mutex
  • 需要更简单语义:Mutex