Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#: How can I make an IEnumerable<T> thread safe?

Say I have this simple method:

public IEnumerable<uint> GetNumbers() {     uint n = 0;     while(n < 100)         yield return n++; } 

How would you make this thread safe? And by that I mean that you would get that enumerator once, and have multiple threads handle all the numbers without anyone getting duplicates.

I suppose a lock needs to be used somewhere, but where must that lock be for an iterator block to be thread safe? What, in general, do you need to remember if you want a thread safe IEnumerable<T>? Or rather I guess it would be a thread safe IEnumerator<T>...?

like image 936
Svish Avatar asked Oct 22 '09 08:10

Svish


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

Is C language easy?

Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.

What is C language?

C is an imperative procedural language supporting structured programming, lexical variable scope, and recursion, with a static type system. It was designed to be compiled to provide low-level access to memory and language constructs that map efficiently to machine instructions, all with minimal runtime support.

What is C full form?

Full form of C is “COMPILE”. One thing which was missing in C language was further added to C++ that is 'the concept of CLASSES'.


2 Answers

There's an inherent problem in doing so, because IEnumerator<T> has both MoveNext() and Current. You really want a single call such as:

bool TryMoveNext(out T value) 

at that point you can atomically move to the next element and get a value. Implementing that and still being able to use yield could be tricky... I'll have a think about it though. I think you'd need to wrap the "non-threadsafe" iterator in a thread-safe one which atomically performed MoveNext() and Current to implement the interface shown above. I don't know how you'd then wrap this interface back into IEnumerator<T> so that you could use it in foreach though...

If you're using .NET 4.0, Parallel Extensions may be able to help you - you'd need to explain more about what you're trying to do though.

This is an interesting topic - I may have to blog about it...

EDIT: I've now blogged about it with two approaches.

like image 150
Jon Skeet Avatar answered Sep 21 '22 20:09

Jon Skeet


I just tested this bit of code:

static IEnumerable<int> getNums() {     Console.WriteLine("IENUM - ENTER");      for (int i = 0; i < 10; i++)     {         Console.WriteLine(i);         yield return i;     }      Console.WriteLine("IENUM - EXIT"); }  static IEnumerable<int> getNums2() {     try     {         Console.WriteLine("IENUM - ENTER");          for (int i = 0; i < 10; i++)         {             Console.WriteLine(i);             yield return i;         }     }     finally     {         Console.WriteLine("IENUM - EXIT");     } } 

getNums2() always calls the finally part of the code. If you want your IEnumerable to be thread safe, add whatever thread locks you want instead of writelines, wither using ReaderWriterSlimLock, Semaphore, Monitor, etc.

like image 31
Dr. K Avatar answered Sep 21 '22 20:09

Dr. K