2012-12-05 1 views
6

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

foreach(var person in personList) 
{ 
    if (person.Name == "Mehran") 
     break; 
} 

которой personList разделяется между несколькими потоками.

В каких случаях это возможно для person быть null и я получаю NullReferenceException для person.Name?

Как я знаю, человек рассматривается как локальная переменная здесь, и если мы получим в foreach блок, поэтому мы итерация в personList успешно, поэтому person не должно быть пустым ни при каких обстоятельствах или любого параллельного сценария.

Даже если personList изменен другой нитью или указанная ссылка person, переменная person должна иметь значение. Поскольку никто не имеет доступа к изменениям, на которые ссылается person.

Есть ли какой-либо сценарий для объяснения ситуации?

ответ

11

Как я знаю, человек рассматривается как локальная переменная здесь, и если мы получим в блок Еогеасп, поэтому мы итерация в personList успешно, поэтому человек не должен быть пустым ни при каких обстоятельствах или любого параллельного сценария ,

Просто потому, что вы итерации свыше personList не означает, что он не содержит никаких нулевых значений. Например:

List<Person> personList = new List<Person>(); 
personList.Add(null); 

foreach (var person in personList) 
{ 
    // Here, person will be null 
} 

(Кроме того, если что-нибудь модифицирует список, вы вообще в беде - они не поточно- в лице писателей - но я не думаю, что потребности чтобы быть частью проблемы.)

+0

Wooops! списки могут принимать значения null! Параллельные ситуации заставляли меня думать сложнее, чем требовалось! Большое спасибо. – mehrandvd

+0

Да, я знаю о проблемах изменения списка в параллельных ситуациях. Я думаю, ваш простой и быстрый ответ разрешит его. Я проверю наличие возможных нулей в списке. – mehrandvd

3

Переменная не изменяется. Итератора используется для реализации foreach конструкции не поточно:

Из документации List<T>.IEnumerable<T>.GetEnumerator() найдено here:

Перечислитель остается действительным до тех пор, пока коллекция остается неизменной. Если в коллекцию внесены изменения, такие как добавление, изменение или удаление элементов, перечислитель безвозвратно аннулирован и его поведение не определено.

Перечислитель не имеет эксклюзивного доступа к коллекции; поэтому перечисление через коллекцию по существу не является поточно-безопасной процедурой. Чтобы гарантировать безопасность потока во время перечисления, вы можете заблокировать сбор во время всего перечисления. Чтобы обеспечить доступ к коллекции несколькими потоками для чтения и записи, вы должны реализовать свою собственную синхронизацию.

По умолчанию реализации коллекций в пространстве имен System.Collections.Generic не синхронизированы.

Вы всегда должны блокировать списки, итерации по ним, если существует вероятность, что другой поток может изменить список.