I understand that in general a List is not thread safe, however is there anything wrong with simply adding items into a list if the threads never perform any other operations on the list (such as traversing it)?
Example:
List<object> list = new List<object>(); Parallel.ForEach(transactions, tran => { list.Add(new object()); });
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.
A list can be made thread-safe using a mutual exclusion (mutex) lock. Specifically, each add, delete, update, and read of the list must be protected by a lock.
NET Framework 4 introduces the System. Collections. Concurrent namespace, which includes several collection classes that are both thread-safe and scalable. Multiple threads can safely and efficiently add or remove items from these collections, without requiring additional synchronization in user code.
In fact, by default, classes are not thread-safe. Being thread-safe would mean that any operation modifying the list would need to be interlocked against simultaneous access. This would be necessary even for those lists that will only ever be used by a single thread. That would be very inefficient.
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.
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With