views:

784

answers:

8

Hello everyone, How do I find out which function or target is modifying the items in a foreach loop in a multithreaded application?

I continously keep getting the error "Collection was modified; enumeration operation may not execute". I'm not removing or adding any items to the generic list within the for loop. I want to find out how it is getting modified. What is the best way to do this?

Thanks

A: 

The best way to do this is to not expose the collection to many classes which could possibly change it. Make it private to one particular class, then only the methods of that class could possibly change it.

Otherwise, you would need to create a derived class from the collection class, and override all the methods that could update the collection. Set breakpoints at all the overrides.

John Saunders
A: 

Would it be feasible to copy the contents of the global collection to a more tightly scoped variable to protect outside meddling with the data?

Tommi Forsström
A: 

This is not a direct answer, just a suggestion that might help - in a multithreaded situation where a collection might get modified during iteration, I usually use the ToArray method to create a snapshot of the list for iteration:

foreach (object x in list.ToArray()) ...
JayMcClellan
+1  A: 

Replace the collection with an ObservableCollection, attach events to modifications and break on them in the debugger (or capture stack trace etc.).

Richard
A: 

You should be able to set an exception breakpoint, then it's simply a matter of going through each thread to see which one modified the collection. In any case if the collection is shared amongst multiple threads it will need to be properly synchronised.

CurtainDog
A: 

You might want to try out the ObservableCollection class for this. There are some examples for making this thread safe as well.

Øyvind Skaar
A: 

You may also try changing the class name of your collection to see where it is all referenced.

Mike C.
+5  A: 

Wait a minute - I think we've all missed the point.

The collection classes are not thread-safe. If the collection is being accessed by multiple threads without thread-locking, then you need to fix that. It's a particularly insidious problem because it will work correctly [edit - or throw a predictable exception] 99.999% of the time, and 0.001% of the time it will do something totally unpredictable and nearly impossible to reproduce.

A simple approach is to use lock{} statements around EVERY place where ANY code accesses the collection. That may be slight overkill but it is the safest plan. For iteration you can either put a lock around the whole loop or if you don't want to block out other threads that long, just lock it long enough to make a snapshot:

object[] snap;
lock (list)
{
   snap = list.ToArray();
}
foreach (object x in snap) ...
JayMcClellan
Concurrency is not required to get this problem. A method called inside the loop could lead to code that modifies the collection.
Richard
Yes absolutely. I don't think the exception is likely a threading problem since it happens consistently. I'm just saying the lack of thread locking is is very worrisome because it may "seem" to work but it's a little ticking time bomb if multiple threads are indeed accessing the collection with no locking.
JayMcClellan