Есть ли проблема безопасности потоков в этом коде ObjectBuilder?

Я подозреваю проблему со старой версией ObjectBuilder, которая когда-то была частью проекта расширения WCSF, а тем временем переместилась в Unity. Я не уверен, на правильном ли я пути или нет, поэтому я надеюсь, что у кого-то есть более компетентные навыки безопасности потоков, чтобы объяснить, может ли это быть проблемой или нет.

Я использую эту (устаревшую) реализацию ObjectBuilder в веб-приложении ASP.Net WCSF и редко вижу в журналах, что ObjectBuilder жалуется на то, что определенное свойство класса не может быть введено по какой-либо причине, проблема всегда в том, что это свойство ни в коем случае нельзя вводить. Собственность и класс постоянно меняются. Я проследил код до метода, в котором словарь используется для хранения информации о том, обрабатывается ли свойство ObjectBuilder или нет.

Мой вопрос в основном сводится к следующему: есть ли проблема безопасности потоков в следующем коде, которая может привести к тому, что ObjectBuilder получит несогласованные данные из своего словаря?

Класс, который содержит этот код (ReflectionStrategy.cs), создается как Singleton, поэтому все запросы к моему веб-приложению используют этот класс для создания объектов представления/страницы. Его словарь — это приватное поле, используемое только в этом методе и объявленное следующим образом:

private Dictionary<int, bool> _memberRequiresProcessingCache = new Dictionary<int, bool>();

private bool InnerMemberRequiresProcessing(IReflectionMemberInfo<TMemberInfo> member)
{
    bool requires;

    lock (_readLockerMrp)
    {
        if (!_memberRequiresProcessingCache.TryGetValue(member.MemberInfo.GetHashCode(), out requires))
        {
            lock (_writeLockerMrp)
            {
                if (!_memberRequiresProcessingCache.TryGetValue(member.MemberInfo.GetHashCode(), out requires))
                {
                    requires = MemberRequiresProcessing(member);
                    _memberRequiresProcessingCache.Add(member.MemberInfo.GetHashCode(), requires);
                }
            }
        }
    }
    return requires;
}  

Этот код выше не является последней версией, которую вы можете найти на Codeplex, но я все же хочу знать, может ли это быть причиной моих исключений ObjectBuilder. Пока мы разговариваем, я работаю над обновлением, чтобы заменить этот старый код последней версией. Это последняя реализация, к сожалению, я не могу найти никакой информации, почему она была изменена. Может из-за бага, может из-за производительности...

private bool InnerMemberRequiresProcessing(IReflectionMemberInfo<TMemberInfo> member)
{
  bool requires;

  if (!_memberRequiresProcessingCache.TryGetValue(member.MemberInfo, out requires))
  {
    lock (_writeLockerMrp)
    {
      if (!_memberRequiresProcessingCache.TryGetValue(member.MemberInfo, out requires))
      {
        Dictionary<TMemberInfo, bool> tempMemberRequiresProcessingCache =
          new Dictionary<TMemberInfo, bool>(_memberRequiresProcessingCache);
        requires = MemberRequiresProcessing(member);
        tempMemberRequiresProcessingCache.Add(member.MemberInfo, requires);
        _memberRequiresProcessingCache = tempMemberRequiresProcessingCache;
      }
    }
  }
  return requires;
}

person Eulinky    schedule 26.06.2013    source источник
comment
Также полезно было бы предложить, как настроить тест, который может ответить, подвержен ли этот код ошибкам многопоточности.   -  person Eulinky    schedule 28.06.2013


Ответы (1)


  1. Использование хеш-кода выглядит проблематично, если вы запускаете очень большое количество классов/членов, как это может произойти с упомянутым вами одноэлементным подходом.
  2. Двойная блокировка была совершенно странной в старой (во всех случаях на весь раздел идет только одна нить). Обратите внимание, что блокировка в первую очередь, безусловно, снижает производительность. Обратите внимание, что вместо этого они создают копию, чтобы избежать изменения списка во время его чтения.
person eglasius    schedule 29.06.2013
comment
Я настроил синтетический нагрузочный тест для генерации большого количества классов, как многопоточных, так и однопоточных, и оказалось, что это хэш-код, вызывающий коллизии даже при настройке одного потока. Таким образом, нет никаких доказательств проблемы многопоточности. Спасибо, Эгласиус! - person Eulinky; 04.07.2013
comment
Я хочу добавить, что с примерно 200 различными классами и 16 000 членов я столкнулся с коллизией не позднее, чем после генерации 9 миллионов объектов, что означает примерно через 30 минут в моем приложении. хотя последняя реализация кода работает нормально. - person Eulinky; 04.07.2013
comment
Прекрасно работает не подходит: новый код намного медленнее, особенно из-за создания временного словаря — чем больше у вас потоков, тем медленнее строит ObjectBuilder. Теперь мы используем новый код, но избегаем временного словаря и пишем напрямую в него. Обширные тесты показали, что до сих пор проблем не возникало, хотя больше нет блокировки чтения, возможно, из-за того, что dict был объявлен изменчивым. - person Eulinky; 05.07.2013