Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modification of a local variable to null, via another thread, how is that possible

While I'm working on parallelism of our framework, I've confronted a strange condition which I can't imagine why! I simplified the situation to describe it easy. consider this code:

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

which the personList is shared between multiple threads.

In what circumstances is it possible for person to be null and I get the NullReferenceException for person.Name?

As I know, the person is considered as a local variable here and if the we get into the foreach block, so we have iterated the personList successfully, so person should not be null in any circumstances or any parallel scenario.

Even if the personList is changed by another thread, or the referenced person is disposed, the person variable should have a value. Because no one has access to change where the person is referenced to.

Is it any scenario to explain the situation?

like image 948
mehrandvd Avatar asked Dec 05 '12 17:12

mehrandvd


2 Answers

As I know, the person is considered as a local variable here and if the we get into the foreach block, so we have iterated the personList successfully, so person should not be null in any circumstances or any parallel scenario.

Just because you're iterating over personList successfully doesn't mean it doesn't contain any null values. For example:

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

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

(Additionally, if anything is modifying the list, you're generally in trouble - they're not thread-safe in the face of writers - but I don't think that needs to be part of the problem.)

like image 146
Jon Skeet Avatar answered Nov 14 '22 21:11

Jon Skeet


The variable is not modified. The iterator used to implement the foreach construct is not thread safe:

From the documentation of List<T>.IEnumerable<T>.GetEnumerator() found here:

An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and its behavior is undefined.

The enumerator does not have exclusive access to the collection; therefore, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.

Default implementations of collections in the System.Collections.Generic namespace are not synchronized.

You should always lock lists while iterating over them if the possibility that another thread might modify the list exists.

like image 33
Hristo Iliev Avatar answered Nov 14 '22 23:11

Hristo Iliev