.net Dictionary.Resize()异常 - 线程安全?

Nir*_*Nir 3 .net dictionary thread-safety c#-3.0


我们有一个非常严重的问题,每分钟造成数千个异常.我们有一个运行本土缓存机制的网站,该机制以下列形式保存数据:

protected static IDictionary<int, IList<IInterfaceForData>> m_Data = null;
Run Code Online (Sandbox Code Playgroud)

当我们在这个字典上调用Add时,我们得到一个非常奇怪的行为:" 索引超出了数组的范围 ",当密钥100%不在字典中时:

m_Data.Add(id, new List<IInterfaceForData>());
Run Code Online (Sandbox Code Playgroud)

我们使用这样的锁来保护这个电话:

if(Monitor.TryEnter(m_LockObj, 1000))
{
   try
   {
       m_Data.Add(id, new List<IInterfaceForData>());
   }
   catch(Exception ex)
   {                                   
        // log exception
   }
   finally
   {
      Monitor.Exit(m_LockObj);
   }
}
Run Code Online (Sandbox Code Playgroud)

我们得到这个例外:

   at System.Collections.Generic.Dictionary`2.Resize()     at   System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)       at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)     
Run Code Online (Sandbox Code Playgroud)

我们找不到任何解释,因为异常与Dictionary的线程安全有关,我们(认为我们)是线程安全的.我们在每个Add()和Remove()调用上使用lock()或Monitor.TryEnter,m_Data.TryGetValue(...)除外

任何帮助将不胜感激.

非常感谢.

Fra*_*ega 6

似乎在某些时候代码没有被锁定而且集合被更改了......你看过System.Collections.Concurrent命名空间了吗?特别是ConcurrentDictionary类?它是线程安全的,可能会让你免受诸如此类或竞争条件等奇怪错误的痛苦

它几乎像常规字典一样工作,除了对于大多数操作你使用"try"方法,即TryGetValue这将尝试获取值并返回True操作是否有效,False如果没有,你当然可以检查这个值继续用你的逻辑

你应该检查这个msdn链接,它与你正在做的非常相似:

使用ConcurrentDictionary实现缓存

提问者目前正在使用带有a的非并发字典,ReaderWriterLockSlim并将其更改为并发字典.