【问题标题】:Can querying a static dictionary cause threading issues?查询静态字典会导致线程问题吗?
【发布时间】:2018-01-12 07:09:06
【问题描述】:

我有一个类似的类(下面的简化版)

public static class ThingyLookup
{
     private static ConcurrentDictionary<int, Thingy> cache;

     public static UpsertThingies (IEnumerable<Thingy> thingies)
     {
         foreach (var thingy in thingies)
         {
              if (thingy.Status == ThingyStatus.Deleted)
              {
                   Thingy removed;
                   cache.TryRemove(thingy.Id, out removed);
              }
              else
              {
                   cache.TryUpdate(thingy.Id, thingy);
              }
         }
     }

     public static IEnumerable<Thingy> Find (string query)
     {
         return (from thingy in cache.Values
                 where thingy != null && thingy.Name.Contains(query)
                 orderby thingy.Name
                 select thingy);
     }
}

如果 2 个线程正在运行 Find 查询,是否有可能发生类似

  • 线程 1 评估 thingy != null &amp;&amp; thingy.Name.Contains(query) 为真的情况
  • 线程 2 将字典中相同的 thingy 更新为 null
  • 线程 1 尝试在 orderby 中使用 thingy.Name,从而导致 NRE

??如果是这样,如何在不造成死锁的情况下进行预防?

【问题讨论】:

  • 我假设Find 中的thingies 应该是cache?如果您的示例是可编译的,那就太好了。
  • thingy 中的 UpsertThingies 怎么可能是 null 而不会导致 cache.TryUpdate 抛出 NRE?话虽如此,不可能将nul 添加到您的字典中。
  • @Damien_The_Unbeliever 我现在修好了。对不起。

标签: c# .net multithreading concurrency


【解决方案1】:

您的具体情况不是问题。 Find 中的 thingy 变量分配了对各种对象的引用。在另一个上下文中运行的任何内容都无法更改该变量中包含的引用,因此它永远不会从非null 变为null

【讨论】:

    【解决方案2】:

    简短回答:不,您描述的场景是不可能的。 要了解为什么让我们深入了解 ConcurrentDictionary 实现细节。 当您调用 cache.Values 时,ConcurrentDictionary 会调用 AcquireAllLocks 阻止我们修改集合(通过 cache.TryRemove,例如)在值集合创建期间,创建一个 List,将现有值放入创建的列表中(如果 TValue 是引用类型,那么它只是复制引用,而不是克隆对象)和然后将创建的列表包装到 ReadOnlyCollection 中。所以在调用 Find 方法之后,你就有了一个基于值列表的迭代器。此列表不是 ConcurrentDictionary 的一部分,因此任何 cache.TryRemovecache.TryUpdate 都不会更改列表(以及查找方法)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-16
      • 2017-03-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多