<T> thread safety list

I am using the code below

var processed = new List<Guid>(); Parallel.ForEach(items, item => { processed.Add(SomeProcessingFunc(item)); }); 

Is the above code stream safe? Is there a chance that the processed list will be corrupted? Or should I use lock before adding?

 var processed = new List<Guid>(); Parallel.ForEach(items, item => { lock(items.SyncRoot) processed.Add(SomeProcessingFunc(item)); }); 

thank.

+22
list c # task-parallel-library parallel-extensions
Feb 16 '11 at 18:22
source share
6 answers

No! This is unsafe because processed.Add not. You can do the following:

 items.AsParallel().Select(item => SomeProcessingFunc(item)).ToList(); 

Keep in mind that Parallel.ForEach was created primarily for imperative operations for each element of a sequence. What you do is map: project each value of the sequence. For this, Select was created. AsParallel scales it most efficiently across streams.

This code works correctly:

 var processed = new List<Guid>(); Parallel.ForEach(items, item => { lock(items.SyncRoot) processed.Add(SomeProcessingFunc(item)); }); 

but it doesn't make sense in terms of multithreading. lock at each iterative force is completely sequential execution, the chain of threads will wait for a single thread.

+23
Feb 16 '11 at 18:25
source share

Using:

 var processed = new ConcurrentBag<Guid>(); 

See the parallel foreach loop - odd behavior .

+6
Feb 16 '11 at 18:27
source share

To quote Jon Skeet before he gets here:

As part of the Parellel extensions in .Net 4, there are several new collections in the new System.Collections.Concurrent Namespace. They are designed to be safe in the face of simultaneous operations from multiple threads, with relatively little blockage.

These include, but are not limited to, IProducerConsumerCollection<T>, BlockingCollection<T>, ConcurrentBag<T>, ConcurrentQueue<T>, ConcurrentStack<T>, and ConcurrentDictionary<TKey, TValue> .

+4
Feb 16 '11 at 18:27
source share

Using a ConcurrentBag of Something Type

 var bag = new ConcurrentBag<List<Something>>; var items = GetAllItemsINeed(); Parallel.For(items,i => { bag.Add(i.DoSomethingInEachI()); }); 
+1
Jan 24 '16 at 17:07
source share

reading is thread safe, but adding is not. You need to set a read / write lock, since adding can lead to a resizing of the internal array, which would ruin the simultaneous reading.

If you can guarantee that the array will not change size when adding, you can be safe to add while reading, but don't quote me on this.

But actually a list is just an interface to an array.

0
Feb 16 '11 at 18:39
source share

Alternatively, Andrei's answer :

 items.AsParallel().Select(item => SomeProcessingFunc(item)).ToList(); 

You can also write

 items.AsParallel().ForAll(item => SomeProcessingFunc(item)); 

This makes the query behind it even more efficient because it does not require a merge, MSDN . Make sure the SomeProcessingFunc function is thread safe. And I think, but did not check it, that you still need a lock if the list can be changed in another thread (adding or removing) elements.

0
Aug 07 2018-12-12T00:
source share



All Articles