问题描述
我目前正在实现多客户端键值存储(例如redis或memcached),它允许客户端获得对该存储的独占访问权限。
现在我有一个问题,当从共享存储中获取值时,它可以由RwLockWriteGoard(当独占访问处于活动状态时)保护,而不受RwLockReadGuard的保护。
我没有找到一种将存储存储在变量中以稍后对其执行操作的方式,而这种方式并不关心存储是受读保护还是写保护。
这是我目前使用的简化解决方案。
// Assume Store is like this
let store = Arc::new(RwLock::new(HashMap::new()));
// --snip--
let mut exclusive_access: Option<RwLockWriteGuard<HashMap<String,String>>> = None;
while !is_finished {
// --snip--
let response = match parse_command(&command) {
Command::Get(key) => {
let read_result = match exclusive_access {
Some(exclusive_store) => match exclusive_store.get(&key) {
Some(x) => Some(x.clone()),None => None,},None => match store.read().unwrap().get(&key) {
Some(x) => Some(x.clone()),};
// simplified
read_result
}
// --snip--
};
if gain_exclusive_access {
exclusive_access = Some(store.write().unwrap());
} else {
exclusive_access = None;
}
}
如果可能的话,我想将Command :: Get(key)臂写成这样:
let store = match exclusive_access {
Some(store) => store,None => store.read().unwrap()
};
store.get(&key)
但这是行不通的,因为匹配的两个臂返回不同的类型(RwLockWriteGuard和RwLockReadGuard)。
有没有办法解决这个问题,我实在太盲目了?
解决方法
使用枚举作为标记的联合。
use std::sync::{RwLock,RwLockReadGuard,RwLockWriteGuard};
enum LockWrapper<'a,T>{
Read(RwLockReadGuard<'a,T>),Write(RwLockWriteGuard<'a,T>)
}
impl<'a,T> Deref for LockWrapper<'a,T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
LockWrapper::Read(read_guard) => read_guard.deref(),LockWrapper::Write(write_guard) => write_guard.deref()
}
}
}
fn main() {
let lock: RwLock<i32> = RwLock::new(0);
let condition = false;
let guard = match condition{
true=>LockWrapper::Read(lock.read().unwrap()),false=>LockWrapper::Write(lock.write().unwrap())
};
// Now guard holds either read or write lock.
}