如何以线程安全方式获取嵌套RwLock并解决Rust客户数据更新编译问题?
线程安全的客户数据更新实现问题
我通过以下结构以线程安全的方式管理客户数据:
customer_id_to_data: Arc<RwLock<HashMap<CustomerId, Arc<RwLock<CustomerData>>>>>
我的原则是除非绝对必要(仅在创建或删除新CustomerId时),否则绝不获取HashMap的写锁。
我需要实现一个添加或更新单个CustomerData的函数,最初的实现如下:
fn load_customer_data_impl( customer_id_to_data: &Arc<RwLock<HashMap<CustomerId, Arc<RwLock<CustomerData>>>>>, customer_id: &CustomerId, new_data: CustomerData, ) -> () { if !{ let read_guard = Self::get_customer_id_to_data_read_guard(customer_id_to_data); if !read_guard.contains_key(customer_id) { false } else { let mut data_write_guard = read_guard .get(customer_id) .unwrap() // 已经检查过,此时仍持有读锁 .write() .unwrap_or_else(|| sys::process::exit(1)); *data_write_guard = new_data; // 注:原代码中的new_index应为new_data true } } { let mut write_guard = Self::get_customer_id_to_data_write_guard(customer_id_to_data); write_guard.insert(*customer_id, Arc::new(RwLock::new(new_data))); } }
这个实现原本希望满足三个必要条件:
- 在检查
contains_key和调用.get().unwrap()期间不释放读锁 - 在获取HashMap的写锁前,读锁已超出作用域
new_data只能被移动一次,要么在if子句中更新现有数据,要么在if主体中插入新数据
但编译器针对第三个条件报错:它无法识别如果new_data已在if子句中被移动,就不会进入if主体的逻辑,因此认为new_data可能被多次移动。我尝试重新组织代码,但始终无法解决这个问题。
我试过两种朴素写法,但都存在竞态条件:
第一种写法:
if Self::get_customer_id_to_data_read_guard(customer_id_to_data).contains_key(customer_id) { let read_guard = Self::get_customer_id_to_data_read_guard(customer_id_to_data); let mut data_write_guard = read_guard .get(customer_id) .unwrap() // 之前检查过,但此时读锁已释放并重新获取,存在竞态 .write() .unwrap_or_else(|| sys::process::exit(1)); *data_write_guard = new_data; } else { let mut write_guard = Self::get_customer_id_to_data_write_guard(customer_id_to_data); write_guard.insert(*customer_id, Arc::new(RwLock::new(new_data))); }
问题在于if子句中的读锁在进入if主体前就已释放,重新获取读锁的间隙可能有其他线程删除该CustomerId,导致.unwrap() panic。
第二种写法同样存在竞态:
if !get_read_lock().contains_key(...) { get_write_lock().insert(...); } else { *get_read_lock().get(...).write(...) = new_data; }
在检查if条件和进入else主体的间隙,其他线程可能删除该CustomerId,导致后续获取数据时出错。
我了解if-let-chains RFC,但不知道不使用它的情况下,如何写出满足所有条件的正确实现。
内容的提问来源于stack exchange,提问作者gmoss
相关产品推荐
相关产品推荐

