Modifying list from another thread while iterating (C#) Modifying list from another thread while iterating (C#) multithreading multithreading

Modifying list from another thread while iterating (C#)


What is the best way to handle this (I would perfer it to be rather simple even at the cost of performance)?

Fundamentally: don't try to modify a non-thread-safe collection from multiple threads without locking. The fact that you're iterating is mostly irrelevant here - it just helped you find it quicker. It would have been unsafe for two threads to both be calling Remove at the same time.

Either use a thread-safe collection such as ConcurrentBag or make sure that only one thread does anything with the collection at a time.


Method #1:

The simplest and least efficient method is to create a critical section for the readers and writers.

// Writerlock (aList){  aList.Remove(item);}// Readerlock (aList){  foreach (T name in aList)  {    name.doSomething();  }}

Method #2:

This is similar to method #1, but instead of holding the lock for the entire duration of the foreach loop you would copy the collection first and then iterate over the copy.

// Writerlock (aList){  aList.Remove(item);}// ReaderList<T> copy;lock (aList){  copy = new List<T>(aList);}foreach (T name in copy){  name.doSomething();}

Method #3:

It all depends on your specific situation, but the way I normally deal with this is to keep the master reference to the collection immutable. That way you never have to synchronize access on the reader side. The writer side of things needs a lock. The reader side needs nothing which means the readers stay highly concurrent. The only thing you need to do is mark the aList reference as volatile.

// Variable declarationobject lockref = new object();volatile List<T> aList = new List<T>();// Writerlock (lockref){  var copy = new List<T>(aList);  copy.Remove(item);  aList = copy;}// ReaderList<T> local = aList;foreach (T name in local){  name.doSomething();}


Thread A:

lock (aList) {  foreach (Type name in aList) {     name.doSomething();  }}

Thread B:

lock (aList) {  aList.Remove(Element);}

This ofcourse is really bad for performance.