To highlight what problems can appear when we use nonthread safe collections in a concurrent program, let's write a simple program that will use the Parallel.Foreach
class to copy a collection and double its elements:
var source = Enumerable.Range(1, 42000).ToList(); var destination = new List<int>(); Parallel.ForEach(source, n => destination.Add(n * 2)); Assert.AreEqual(source.Count, destination.Count);
If we run this code, we will almost certainly get the AggregateException
exception with the ArgumentException
instance wrapped inside it.
This happens because the Add
method of the List<T>
class is not thread safe, and the reason for this lies in the implementation details:
public void Add(T item) { if (_size == _items.Length) EnsureCapacity(_size + 1); _items[_size++] = item; _version++; }
In case the concurrent threads access this method when the _size == items.Length – 1
condition is true, the ArgumentException...