什么是在Rust中具有线程安全的懒惰初始化可能可变值的正确方法?

时间:2018-02-18 05:00:58

标签: rust synchronization thread-safety lazy-initialization

我有一个包含一个初始化相当昂贵的字段的结构,所以我希望能够懒得这样做。但是,在采用&self的方法中,这可能是必要的。该字段还需要能够在初始化后进行修改,但这只会在采用&mut self的方法中进行。

在Rust中执行此操作的正确方法(如惯用语和线程安全方式)是什么?在我看来,这两个约束中的任何一个都是微不足道的:

  • 如果它只需要懒惰地初始化,而不是变异,我可以简单地使用lazy-initLazy<T>类型。
  • 如果它只需要是可变的而不是懒惰的,那么我可以使用正常的字段(显然)。

但是,我不太清楚如何处理两者。 RwLock似乎是相关的,但看起来在lazy-init的源代码中我看到了线程安全的延迟初始化是相当棘手的,所以我对基于它推出自己的解决方案犹豫不决

1 个答案:

答案 0 :(得分:3)

最简单的解决方案是RwLock<Option<T>>

  

但是,我不太清楚如何处理两者。 RwLock似乎是相关的,但看起来在lazy-init的源代码中我看到了线程安全的延迟初始化是相当棘手的,所以我对根据它推出自己的解决方案犹豫不决

lazy-init使用棘手的代码,因为它保证了创建后的无锁访问。无锁总是有点棘手。

请注意,在Rust中很容易判断某些内容是否棘手:棘手意味着使用unsafe块。由于您可以使用RwLock<Option<T>>而没有任何不安全的阻止,因此您无需担心。

如果要捕获初始化一次的闭包,可能需要RwLock<Option<T>>的变体,而不是必须在每个潜在的初始化调用站点传递它。

在这种情况下,您需要RwLock<SimpleLazy<T>>之类的地方:

enum SimpleLazy<T> {
    Initialized(T),
    Uninitialized(Box<FnOnce() -> T>),
}

您无需担心SimpleLazy<T> Sync,因为RwLock会照顾您。{/ p>