List.Add() thread safety

I solved my problem using ConcurrentBag<T> instead of List<T> like this:

ConcurrentBag<object> list = new ConcurrentBag<object>();
Parallel.ForEach(transactions, tran =>
{
    list.Add(new object());
});

You current approach is not thread-safe - I would suggest avoiding this altogether - since you basically do a data transformation PLINQ might be a better approach ( I know this is a simplified example but in the end you are projecting each transaction into another "state" object).

List<object> list = transactions.AsParallel()
                                .Select( tran => new object())
                                .ToList();

Behind the scenes lots of things happen, including reallocating buffers and copying elements. That code will cause danger. Very simply, there are no atomic operations when adding to a list, at the least the "Length" property needs to be updates, and item needs to be put in at the right location, and (if there's a separate variable) the index needs to be updated. Multiple threads can trample over each other. And if a grow is required then there is lots more going on. If something is writing to a list nothing else should be reading or writing to it.

In .NET 4.0 we have concurrent collections, which are handily threadsafe and don't require locks.


If you want to use List.add from multiple threads and do not care about the ordering, then you probably do not need the indexing ability of a List anyway, and should use some of the available concurrent collections instead.

If you ignore this advice and only do add, you could make add thread safe but in unpredictable order like this:

private Object someListLock = new Object(); // only once

...

lock (someListLock)
{
    someList.Add(item);
}

If you accept this unpredictable ordering, chances are that you as mentioned earlier do not need a collection that can do indexing as in someList[i].

Tags:

C#

Asp.Net