Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is enumerator thread safe after getting with lock?

I am wondering if the returned enumerator is thread safe:

public IEnumerator<T> GetEnumerator()
{
    lock (_sync) {
        return _list.GetEnumerator();
    }
}

If I have multiple threads whom are adding data (also within lock() blocks) to this list and one thread enumerating the contents of this list. When the enumerating thread is done it clears the list. Will it then be safe to use the enumerator gotten from this method.

I.e. does the enumerator point to a copy of the list at the instance it was asked for or does it always point back to the list itself, which may or may not be manipulated by another thread during its enumeration?

If the enumerator is not thread safe, then the only other course of action I can see is to create a copy of the list and return that. This is however not ideal as it will generate lots of garbage (this method is called about 60 times per second).

like image 207
JensB Avatar asked Jan 11 '23 04:01

JensB


2 Answers

No, not at all. This lock synchronizes only access to _list.GetEnumerator method; where as enumerating a list is lot more than that. It includes reading the IEnumerator.Current property, calling IEnumerator.MoveNext etc.

You either need a lock over the foreach(I assume you enumerate via foreach), or you need to make a copy of list.

Better option is to take a look at Threadsafe collections provided out of the box.

like image 62
Sriram Sakthivel Avatar answered Jan 17 '23 20:01

Sriram Sakthivel


According to the documentation, to guarantee thread-safity you have to lock collecton during entire iteration over it.

The enumerator does not have exclusive access to the collection; therefore, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.

Another option, may be define you own custom iterator, and for every thread create a new instance of it. So every thread will have it's own copy of Current read-only pointer to the same collection.

like image 21
Tigran Avatar answered Jan 17 '23 20:01

Tigran