.net Dictionary.Resize () исключение - безопасность потока? - PullRequest
3 голосов
/ 02 марта 2011


У нас очень серьезная проблема, вызывающая тысячи исключений в минуту. У нас есть веб-сайт с собственным механизмом кэширования, который хранит данные в виде:

protected static IDictionary<int, IList<IInterfaceForData>> m_Data = null;

и когда мы вызываем Add в этом словаре, мы получаем очень странное поведение: « Index находился за пределами массива », когда ключ был на 100% отсутствует в словаре:

m_Data.Add(id, new List<IInterfaceForData>());

Мы защищаем этот вызов с помощью блокировки, подобной этой:

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

и мы получаем это исключение:

   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)     

Мы не можем найти никакого объяснения этому, потому что исключение связано с безопасностью потока в словаре, и мы (думаем, что мы) безопасны для потоков. Мы используем lock () или Monitor.TryEnter при каждом вызове Add () и Remove (), за исключением m_Data.TryGetValue (...)

Любая помощь будет принята с благодарностью.

Большое спасибо.

Ответы [ 2 ]

6 голосов
/ 03 марта 2011

Кажется, что в какой-то момент код не заблокирован, а коллекция изменена ... Вы взглянули на пространство имен System.Collections.Concurrent?В частности, класс ConcurrentDictionary ?Это потокобезопасно и, вероятно, избавит вас от множества неприятных ошибок, таких как то или гонки, и т. Д.

Он работает почти как обычный словарь, за исключением того, что для большинства операций вы используете метод "try", т.е.TryGetValue это попытается получить значение и вернуть True, если операция была действительной, и False, если нет, тогда вы, конечно, можете проверить это значение, чтобы продолжить свою логику

Вам следует проверить-вне этой ссылки msdn, она действительно похожа на то, что вы делаете:

Реализация кэша с ConcurrentDictionary

, который в настоящее время запрашивает, использует не параллельный словарь сReaderWriterLockSlim и заменяет его на параллельный словарь.

4 голосов
/ 02 марта 2011

Вам необходимо синхронизировать доступ к вашему m_Data словарю везде , а не только к Add вызовам. Ты это делаешь?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...