【问题标题】:Which members of .NET's ConcurrentDictionary are thread-safe?.NET 的 ConcurrentDictionary 的哪些成员是线程安全的?
【发布时间】:2023-03-22 04:35:01
【问题描述】:

System.Collections.Concurrent.ConcurrentDictionary 的 MSDN 文档说:

线程安全

ConcurrentDictionary<TKey, TValue> 的所有公共和受保护成员都是线程安全的,并且可以从多个线程同时使用。但是,通过ConcurrentDictionary<TKey, TValue> 实现的接口之一访问的成员,包括扩展方法,不能保证是线程安全的,可能需要由调用者同步。

(强调我的)

这似乎是自相矛盾的。 “所有成员都是线程安全的。但成员 [有时] 不是线程安全的。”

我明白扩展方法当然不能保证是线程安全的。

但是“通过其中一个接口访问”是什么意思? TryGetValueIDictionary<TKey, TValue> 接口的成员)是线程安全的吗?

【问题讨论】:

    标签: c# .net multithreading concurrency concurrentdictionary


    【解决方案1】:

    请注意涵盖explicit interface implementations 的文档部分。例如。该类实现IDictionary.Add。此方法不是类的公共或受保护成员,但可以通过IDictionary 接口访问。正是这些成员不能保证是线程安全的。

    【讨论】:

    • 知道为什么会这样吗?
    • @Peter - 好吧,一方面,提供这样的保证没有什么价值,因为如果你通过这样的接口访问它,调用代码不太可能使用保证(因为其他实现不会提供这样的保证)。
    【解决方案2】:

    由于Explicit vs Implicit interface implementation

    如果您查看source code for ConcurrentDictionary<TKey, TValue>,您可能会发现有些方法显式实现了一个接口(如object IDictionary.this[object key]),尽管在内部调用同一操作的线程安全版本,但这种行为可能会改变未来。

    将其视为职责分工: 如果我(作为一个班级)收到ConcurrentDictionary<TKey, TValue> 的实例,我知道以线程安全的方式执行操作是该实例的责任。

    但是,如果我(再次作为一个班级)收到IDictionary<TKey, TValue> 的实例,那么我应该知道是否应该或不应该存在线程安全问题。如果没有这样的顾虑,我只是按原样使用字典,但如果需要线程安全我有责任以线程安全的方式执行所有操作。

    【讨论】:

      【解决方案3】:

      the documentation 中有一个特定部分明确说明ConcurrentDictionary<TKey, TValue> 中并非所有内容都是线程安全的:

      所有这些操作都是原子的,并且对于ConcurrentDictionary<TKey, TValue> 类上的所有其他操作都是线程安全的。唯一的例外是接受委托的方法,即AddOrUpdateGetOrAdd。对于字典的修改和写入操作,ConcurrentDictionary<TKey, TValue> 使用细粒度锁定来确保线程安全。 (对字典的读取操作以无锁方式执行。)但是,这些方法的委托在锁外调用,以避免在锁下执行未知代码可能出现的问题。因此,这些委托执行的代码不受操作的原子性影响。

      所以有一些一般性的排除和特定于ConcurrentDictionary<TKey, TValue> 的一些情况:

      • AddOrUpdateGetOrAdd 上的委托不是以线程安全的方式调用的。
      • 在显式接口实现上调用的方法或属性不能保证是线程安全的;
      • 类上调用的扩展方法不能保证是线程安全的;
      • 对类的公共成员的所有其他操作都是线程安全的。

      【讨论】:

      • 这不是“通常”的标准引用 - 通常只引用静态成员。在这里,针对实例成员提供了更多保证。 (我相信这句话在System.Collections.Concurrent 中很常见)
      • 好的。甚至没有注意到这一点。 @Damien_The_Unbeliever。将删除第一部分,因为它并没有真正添加太多。
      • “所有这些操作”部分位于 ConcurrentDictionary 提供的几个附加方法表的下方,似乎只指那些,不是吗?
      • 确实如此,但您引用的另一部分声明:“所有公共和受保护成员”。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多