开发者

IEnumerable<T> thread safety?

开发者 https://www.devze.com 2023-03-05 04:17 出处:网络
I have a main thread that populates a List<T>.Further I create a chain of objects that will execute on different threads, requiring access to the List.The original list will never be written to

I have a main thread that populates a List<T>. Further I create a chain of objects that will execute on different threads, requiring access to the List. The original list will never be written to after it's generated. My thought was to pass the list as IEnumerable<T> to the objects executin开发者_StackOverflow中文版g on other threads, mainly for the reason of not allowing those implementing those objects to write to the list by mistake. In other words if the original list is guaranteed not be written to, is it safe for multiple threads to use .Where or foreach on the IEnumerable?

I am not sure if the iterator in itself is thread safe if the original collection is never changed.


IEnumerable<T> can't be modified. So what can be non thread safe with it? (If you don't modify the actual List<T>).

For non thread safety you need writing and reading operations.

"Iterator in itself" is instantiated for each foreach.

Edit: I simplified my answer a bit, but @Eric Lippert added valuable comment. IEnumerable<T> doesn't define modifying methods, but it doesn't mean that access operators are thread safe (GetEnumerator, MoveNext and etc.) Simplest example: GetEnumerator implemented as this:

  • Every time returns same instance of IEnumerator
  • Resets it's position

More sophisticated example is caching.

This is interesting point, but fortunately I don't know any standard class that has not thread-safe implementation of IEnumerable.


Each thread that calls Where or foreach gets its own enumerator - they don't share one enumerator object for the same list. So since the List isn't being modified, and since each thread is working with its own copy of an enumerator, there should be no thread safety issues.

You can see this at work in one thread - Just create a List of 10 objects, and get two enumerators from that List. Use one enumerator to enumerate through 5 items, and use the other to enumerate through 5 items. You will see that both enumerators enumerated through only the first 5 items, and that the second one did not start where the first enumerator left off.


As long as you are certain that the List will never be modified then it will be safe to read from multiple threads. This includes the use of the IEnumerator instances it provides.

This is going to be true for most collections. In fact, all collections in the BCL should be stable during enumeration. In other words, the enumerator will not modify the data structure. I can think of some obscure cases, like a splay-tree, were enumerating it might modify the structure. Again, none of the BCL collections do that.


If you are certain that the list will not be modified after creation, you should guarantee that by converting it to a ReadOnlyCollection<T>. Of course if you keep the original list that the read only collection uses you can modify it, but if you toss the original list away you're effectively making it permentantly read only.

From the Thread Safety section of the collection:

A ReadOnlyCollection can support multiple readers concurrently, as long as the collection is not modified.

So if you don't touch the original list again and stop referencing it, you can ensure that multiple threads can read it without worry (so long as you don't do anything wacky with trying to modify it again).


In other words if the original list is guaranteed not be written to, is it safe for multiple threads to use .Where or foreach on the IEnumerable?

Yes it's only a problem if the list gets mutated.

But note than IEnumerable<T> can be cast back to a list and then modified.

But there is another alternative: wrap your list into a ReadOnlyCollection<T> and pass that around. If you now throw away the original list you basically created a new immutable list.


If you are using net framework 4.5 or greater, this could be a great soulution http://msdn.microsoft.com/en-us/library/dd997305(v=vs.110).aspx

(microsoft already implemented a thread safe enumerable)

0

精彩评论

暂无评论...
验证码 换一张
取 消