【问题标题】:ConcurrentDictionary - broken dictionary or bad code?ConcurrentDictionary - 损坏的字典或错误的代码?
【发布时间】:2012-01-05 22:06:32
【问题描述】:

好的,所以我遇到了一个奇怪的小问题,坦率地说我没有想法。我想把它扔出去,看看我是否遗漏了我做错的事情,或者 ConcurrentDictionary 是否工作不正常。代码如下:

(缓存是一个包含静态 ConcurrentDictionary Keys 的类)

var tmp = Cache.Keys.GetOrAdd(type,
                key =>
                {
                    var keys = context.GetKeys(key);
                    if (keys.Count() == 1)
                    {
                        return new KeyInfo
                            {
                                Name = keys.First().Name,
                                Info = key.GetInfo(keys.First().Name)
                            };
                    }

                    return null;
                });

            if (tmp == null)
                Cache.Keys.TryRemove(type, out tmp);

            return tmp;

问题是偶尔tmpnull,导致TryRemove 行运行,但上面的return null; 行从未被命中。既然return null 是唯一将null 放入字典并且它永远不会运行的东西,那么tmp 怎么可能是null


包括 Cache 类(此代码不使用 SetNames):

public class Cache
{
    public static ConcurrentDictionary<Type, Info> Keys = new ConcurrentDictionary<Type, Info>();
    public static ConcurrentDictionary<Type, string> SetNames = new ConcurrentDictionary<Type, string>();
}

【问题讨论】:

  • 也许字典中已经有一个null 值?
  • 有多少线程在运行这段代码?它似乎不是线程安全的。
  • @IlyaKogan - 不,字典在启动时是空的,并且从不包含空值,即使if (tmp == null) 内的断点被命中。
  • @oleksii 我的所有意图都是让它成为线程安全的。您能否具体说明您认为会导致问题的区域?
  • 你确定这条线永远不会被击中吗?断点是在 lambda 中显式设置的,而不是在语句本身上?

标签: c# multithreading concurrency concurrentdictionary


【解决方案1】:

如果您从context.GetKeys(key) 获得的不是单个项目集,则tmp 可以为空。在这种情况下,keys.Count() != 1 和一个 null 项将插入到 Cache.Keys 中,用于指定键(并从 GetOrAdd 返回,并分配给 tmp)。

编辑:只是想到了另一种可能性。什么数据类型是关键?它是某种自定义类吗?看起来是这样。如果是这样,您是否正确实施了EqualsGetHashcode

【讨论】:

  • 但 OP 声明永远不会执行 return null 行,如果正确,则意味着您的场景永远不会发生。
  • @phoog 是正确的 - 我还仔细检查了传入的参数以及 context.GetKeys(key),这种情况不会发生在此数据中。我预计它会在未来发生,但这不是问题。
  • 那么 OP 是错误的 :-) 要么字典包含指定键的空值,要么执行返回空值行。现在,从变量名称来看,我对在 Keys 成员上调用 GetOrAdd 持怀疑态度,但那是另一回事了。
  • @ChrisShain 我明白你在说什么,我一直在试图找出其中的情况。我创建这篇文章的原因是因为在任何情况下这些都不是问题,这是没有意义的。如果Cache.Keys 曾经包含null,则return null 上的断点被破坏。
  • @ChrisShain 关键是一个 .net Type 对象
【解决方案2】:

我应该在不久前关闭它,但我完全忘记了它。由于TryRemove,该示例不是线程安全的,但这只是为了调试目的而添加的。我最终通过重写解决了这个问题,所以也许一些关于代码过时的 cmets 是正确的。但是,验证码不再存在。

我将此归咎于用户错误(当然是我自己的错误)。感谢大家的时间!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-11
    • 1970-01-01
    • 2019-08-23
    • 1970-01-01
    • 2016-01-28
    • 1970-01-01
    • 2016-07-29
    • 1970-01-01
    相关资源
    最近更新 更多