.NET Framework 3.5
I have two threads that using the same generic collection. One thread loop through the collection using the foreach statement:
while(HaveToContinue)
{
// Do work 1
try
{
foreach(var item in myDictionary)
{
// Do something with/to item
}
// Do work 2 (I need to complete the foreach first)
}
catch(InvalidOperationException)
{
}
}
At the same time the other thread modify the collection:
// The following line causes the InvalidOperationException (in the foreach)
myDictionary.Remove(...);
So, is there a way to avoid this InvalidOperationException? If I could avoid this exception I could complete my work (work 1 + work 2) all times, instead, every time I catch the exception, I can’t finish the work.
I thought to use a ManualResetEvent object, something like this:
while(HaveToContinue)
{
// Do work 1
try
{
myResetEvent.Reset();
foreach(var item in myDictionary)
{
// Do something with/to item
}
myResetEvent.Set();
// Do work 2 (I need to complete the foreach first)
}
catch(InvalidOperationException)
{
}
}
And every time the other thread modify the collection:
// Expect the foreach is completed
myResetEvent.WaitOne();
// And then modify the collection
myDictionary.Remove(...);
But probably there is a better solution.
If you’re using .NET 4, you should use the
ConcurrentBagorConcurrentDictionaryclass instead, which are thread-safe.If you’re using an earlier version, then the easiest (albeit inefficient) solution would be to use a
lock. You could instantiate this as a plain object:Then, when you need to access the list, acquire the lock first:
Similarly when modifying the collection, acquiring the same lock:
If the amount of work you have to do on each item is substantial, then it would be more efficient to first obtain a local copy of the dictionary, release the lock, and then proceed to iterate over the said copy, allowing the racing thread to modify the global dictionary: