C# ConcurrentDictionary-坏字典还是坏代码?
好吧,我遇到了一个奇怪的小问题,坦率地说,我已经没有主意了。我想把它扔出去看看我是否遗漏了一些我做错的事情,或者ConcurrentDictionary是否工作不正常。代码如下: (缓存是包含静态ConcurrentDictionary键的类) 问题是偶尔C# ConcurrentDictionary-坏字典还是坏代码?,c#,multithreading,concurrency,concurrentdictionary,C#,Multithreading,Concurrency,Concurrentdictionary,好吧,我遇到了一个奇怪的小问题,坦率地说,我已经没有主意了。我想把它扔出去看看我是否遗漏了一些我做错的事情,或者ConcurrentDictionary是否工作不正常。代码如下: (缓存是包含静态ConcurrentDictionary键的类) 问题是偶尔tmp为null,导致TryRemove行运行,而返回null上面的行永远不会被点击。既然returnnull是唯一将null放入字典的东西,而且它从未运行过,那么tmp怎么可能是null 包括缓存类(此代码不使用SetNames): 公共类
tmp
为null
,导致TryRemove
行运行,而返回null代码>上面的行永远不会被点击。既然returnnull
是唯一将null
放入字典的东西,而且它从未运行过,那么tmp
怎么可能是null
包括缓存类(此代码不使用SetNames):
公共类缓存
{
公共静态ConcurrentDictionary键=新ConcurrentDictionary();
公共静态ConcurrentDictionary SetNames=新ConcurrentDictionary();
}
tmp
如果从上下文.GetKeys(key)
返回的不是单个项,则tmp可以为空。在这种情况下,keys.Count()!=1
,一个空项将插入指定键的缓存.Keys
(并从GetOrAdd
返回,并分配给tmp
)
编辑:只是想到了另一种可能性。关键是什么数据类型?它是某种自定义类吗?看起来是的。如果是这样的话,您是否正确地实现了
Equals
和GetHashcode
?我应该在一段时间前关闭它,但我完全忘记了它。该示例不是线程安全的,因为TryRemove
,但添加该示例只是为了调试目的。最后,我通过重写解决了这个问题,因此,关于代码过时的一些评论可能是正确的。但是,该代码不再存在以进行确认
我把这一点归咎于用户错误(当然是我自己的错误)。谢谢大家的时间 可能字典中已经有一个
null
值?有多少线程正在运行此代码?它似乎不是线程安全的。@Ilykogan-不,字典在启动时是空的,并且从不包含空值,即使遇到if(tmp==null)
中的断点。@oleksii我完全希望它是线程安全的。你能指定你认为会引起问题的区域吗?你确定线永远不会被击中吗?断点是在lambda中显式设置的,而不是在语句本身上设置的?但是OP声明从未执行返回null
行,如果正确,这意味着您的场景永远不会发生。@phoog是正确的-我还仔细检查了传入参数以及上下文.GetKeys(key)
,此数据不会出现这种情况。我希望将来会发生这种情况,但这不是问题所在。那么OP就错了:-)要么字典包含指定键的null,要么执行返回null行。现在,从变量名来看,我对Keys成员的GetOrAdd调用表示怀疑,但那是另一回事了。@ChrisShain我明白你的意思,我一直在努力找出哪一个是这样的。我写这篇文章的原因是因为在任何情况下,这两个都不是问题,这是没有意义的。如果Cache.Keys
曾经包含null
,则return null
上的断点已断开。@chrishain该键是一个.net类型
对象
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;
public class Cache
{
public static ConcurrentDictionary<Type, Info> Keys = new ConcurrentDictionary<Type, Info>();
public static ConcurrentDictionary<Type, string> SetNames = new ConcurrentDictionary<Type, string>();
}