1

语境

作为练习,我尝试在 Rust中重新实现https://github.com/urbanairship/sarlacc-pit 。

Sarlacc-pit 将外部源镜像到内存数据结构(Set/Map/Etc)中。图书馆的客户纯粹根据馆藏进行操作,不知道馆藏内容正在发生变化。

问题

客户端需要保持对集合的不可变引用,而单个更新线程保持可变引用以更新其内容。这直接违反了 rust 的保证,但在这种情况下应该是安全的,具有以下粗略结构:

pub struct Map<K, V> {
  delegate: SomeReferenceType<Arc<HashMap<K, V>>>
}

impl<K, V> Map<K, V> {
  pub fn get(&self, k: &K) -> Option<&V> {
    self.delegate.borrow().get(k)
  } 

  fn update(&mut self, new_delegate: HashMap<K, V>) {
    self.delegate.set(Arc::new(new_delegate));
  }
}

pub struct UpdateService<K, V> {
  collection: Arc<Map<K, V>>
}

impl<K, V> UpdateService<K ,V> {
  pub fn get_collection(&self) -> Arc<Map<K, V>> {
    collection.clone()
  }

  // Called from a thread run on a cadence
  fn update_collection(&mut self) {
    let new_value = /* fetch and process value from backing store */
    self.collection.borrow_mut().update(new_value);
  }
}

我意识到,由于多种原因,这无法编译。

问题的核心是:SomeReferenceType 的类型应该是什么,才能允许这些可变和不可变的引用在没有 ReadWriteLock 之类的东西的情况下共存?我错过了什么吗?

4

1 回答 1

2

如果update_collection从另一个线程调用,你有什么保证主线程不会同时从集合中读取?使用您提供的信息,您需要类似RwLockor的东西Mutex来确保安全。

你已经断言你相信这是安全的。如果您的系统上有一个未公开的约束允许您保证不会发生同时读取和写入,那么可能有一种方法可以将其合并到类型中。但是不能给出更好的答案。

例如,如果更新不频繁,使用集合的三个副本并在每次修改后交换它们可能会满足您的用例:

  1. 一个用于阅读,
  2. 一个用于写作,
  3. 一种用于在交换集合时转换客户端

不过,这不是一个“初学者”级别的 Rust 项目。

于 2019-12-26T02:35:08.643 回答