List<T> thread safety
No! It is not safe at all, because processed.Add
is not. You can do following:
items.AsParallel().Select(item => SomeProcessingFunc(item)).ToList();
Keep in mind that Parallel.ForEach
was created mostly for imperative operations for each element of sequence. What you do is map: project each value of sequence. That is what Select
was created for. AsParallel
scales it across threads in most efficient manner.
This code works correctly:
var processed = new List<Guid>();
Parallel.ForEach(items, item =>
{
lock(items.SyncRoot)
processed.Add(SomeProcessingFunc(item));
});
but makes no sense in terms of multithreading. lock
ing at each iteration forces totally sequential execution, bunch of threads will be waiting for single thread.
Use:
var processed = new ConcurrentBag<Guid>();
See parallel foreach loop - odd behavior.
From Jon Skeet's Book C# in Depth:
As part of Parallel Extensions in .Net 4, there are several new collections in a new
System.Collections.Concurrent
namespace. These are designed to be safe in the face of concurrent operations from multiple threads, with relatively little locking.
These include:
IProducerConsumerCollection<T>
BlockingCollection<T>
ConcurrentBag<T>
ConcurrentQueue<T>
ConcurrentStack<T>
ConcurrentDictionary<TKey, TValue>
- and others