gpt4 book ai didi

c# - 在 ConcurrentDictionary 线程中实现的 IDictionary 成员是否安全?

转载 作者:太空狗 更新时间:2023-10-29 21:14:25 25 4
gpt4 key购买 nike

调用 DoStuffToDictionary(dictionaryTwo) 时,假设方法体内的操作(​​包括索引器)是否安全,LINQ 扩展方法也将是线程安全的?

换句话说,是否会出现跨线程异常或死锁?

var dictionaryOne = new ConcurrentDictionary<int,int>();
var dictionaryTwo = new Dictionary<int,int>();

DoStuffToDictionary(dictionaryOne);
DoStuffToDictionary(dictionaryTwo);

void DoStuffToDictionary(IDictionary<int,int> items) {
// Manipulate dictionary

if (items[0] == -1) {
items[0] = 0; // Dumb example, but are indexers like this OK?
}
}

最佳答案

这段代码有几个问题:

  1. IDictionary接口(interface)可以由任何类型的字典实现
    你的例子肯定不是线程安全的,因为你正在处理 IDictionary<int,int>接口(interface),它不保证任何线程安全。甚至您的代码都通过了 Dictionary和一个 ConcurrentDictionary方法。

  2. 事务需要是原子的才能使它们线程安全
    即使保证字典实现是线程安全的,您的代码也不会是因为您没有锁定对字典的访问在两次调用之间:

    if (items[0] == -1) {
    // <-- another thread can access items in this moment
    items[0] = 0;
    }
  3. 返回 LINQ 查询永远不是线程安全的
    如果您使用 LINQ 返回 IEnumerableIQueriable从你的方法来看,锁几乎没有影响,除非你使用 ToList()立即评估表达式并缓存结果的方法。这是因为 LINQ 仅“准备”执行查询。如果您要返回 IEnumerable从一个方法中,实际字典将在您的方法结束后被访问(因此,在锁之外)。

此代码的最大问题在于您传递了IDictionary。 instance around,这意味着你的代码的其他部分可以直接访问它,并且必须非常小心地锁定同一个锁对象实例。这是痛苦的,正确实现时容易出错,容易意外中断,并且难以检测(竞争条件可能在极少数情况下表现出症状)。

您可以做几件事来改进代码:

  1. 不要传递 IDictionary周围,​​而是您自己的界面(首选)
    使字典成为实现某些自定义接口(interface)的类的私有(private)成员,抽象所有操作,并使用锁来确保线程安全(或在引擎盖下使用 ConcurrentDictionary)。通过这种方式,您可以确保使用相同的锁实例锁定所有调用。

  2. 不使用接口(interface),而是始终传递 ConcurrentDictionary
    这将是线程安全的,只要你使用特定的atomic 方法,ConcurrentDictionary提供( GetOrAddAddOrUpdate 等)。使用像您在示例中所做的那样的简单访问方法将不是线程安全的,这意味着您仍然需要小心使用它。额外的缺点是您将无法在需要时抽象功能(包装/代理字典是不可能的,并且您将无法使用其他字典实现)。

  3. 传递 IDictionary周围,​​并锁定字典本身(完全不推荐)。
    这是一个丑陋的 hack,不幸的是,它的使用频率超过了应有的频率。这意味着您需要在访问此词典的应用程序的每个部分执行此操作,并格外小心地锁定多个操作。

关于c# - 在 ConcurrentDictionary 线程中实现的 IDictionary 成员是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6806303/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com