buciz
buciz

Reputation: 73

How to make ENumerable operations tread safe SynchronizedCollection?

When I use SynchronizedCollection, I can catch the exception

System.InvalidOperationException
Collection was modified; enumeration operation may not execute.

in foreach cycle.

If you look at the source code of SynchronizedCollection class, namely in GetEnumerator method (there is two of them actually one is explicit interface implementation), you’ll see this:

List<T> items;

IEnumerator IEnumerable.GetEnumerator()
{
    return ((IList)this.items).GetEnumerator();
}

public IEnumerator<T> GetEnumerator()
{
    lock (this.sync)
    {
        return this.items.GetEnumerator();
    }
}

It returns enumerator of inner List which is not thread safe!

Edit. I am asking not what can I do in concurrent situations. I am asking

How to make it thread safe?

Upvotes: 0

Views: 212

Answers (2)

buciz
buciz

Reputation: 73

I used SynchronizedCollection class and used foreach (var element in this.items) yield return element; here public new IEnumerator GetEnumerator()

used constructors from base classes and that was enough to make it thread-safe

Upvotes: 0

ryans610
ryans610

Reputation: 11

I think there is two solution for this:

  1. Use ConcurrentBag<T> or other collection in the System.Collections.Concurrent namespace. (Notice that the elements in ConcurrentBag will not be ordered.)
  2. Create a snap shot when retrieving data.

The second one is much safer, in the cost of performance.

If you are using .NetCore, ImmutableList<T> is a better way for snap shot, and can avoid shallow copy problem.

Upvotes: 1

Related Questions