【问题标题】:What's the right way to have a thread-safe lazy-initialized possibly mutable value in Rust?在 Rust 中拥有线程安全的延迟初始化可能可变值的正确方法是什么?
【发布时间】:2018-02-18 05:00:58
【问题描述】:

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

在 Rust 中正确的(如惯用的,以及线程安全的)方法是什么?在我看来,这两个约束中的任何一个都是微不足道的:

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

但是,我不太确定如何处理这两个问题。 RwLock 似乎是相关的,但考虑到我所看到的 lazy-init 的源代码,线程安全的延迟初始化似乎有相当大的技巧,所以我犹豫是否基于它推出自己的解决方案。

【问题讨论】:

  • 试试Lazy<RwLock<T>>

标签: rust synchronization thread-safety lazy-initialization


【解决方案1】:

最简单的解决方案是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&lt;T&gt; Sync,因为RwLock 会为您处理这些问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-11
    • 2019-09-26
    • 2015-10-17
    相关资源
    最近更新 更多