1

I am wondering what will happen if there is a lock inside IEnumerable method.
for example a program like this:

IEnumerable<int> Foo()
{
     ....
     lock(...)
     {
         yield return ...;
     }
}

Since IEnumerable is delay executed, and does not generate all the results at once, what will the lock do inside the method? Will it unlock after each element generation or will it hold on to the lock until the IEnumerable object is GCed? Or something else?

Steve
  • 11,696
  • 7
  • 43
  • 81
  • 2
    http://stackoverflow.com/questions/2847586/yield-returns-within-lock-statement – Pavel Mar 13 '15 at 22:20
  • 1
    Also, there are now [thread safe collections](https://msdn.microsoft.com/en-us/library/dd997305(v=vs.110).aspx) which you can use. It's worth checking out. – bokibeg Mar 13 '15 at 22:26
  • 1
    @Pavel useful reference, also I think this case may be a bit different in sense of locking around single `yield return` - (`foreach(...) {.... lock() {yield return x;}}`) vs. locking around whole generation (`lock(){foreach...` in the linked question. – Alexei Levenkov Mar 13 '15 at 22:31
  • 1
    @bokibeg i only need one element inside the whole collection which means generating the whole collection at once is wasting resource~ but thanks for the comment – Steve Mar 13 '15 at 22:44
  • 1
    @AlexeiLevenkov, I see, good catch! But I do not think it's relevant. At a very simple level the `yield return` is compiled to a class implementing a state machine, or an iterator if you will. Because the return statement is inside the `try {...} finally {...}` block (which `lock {...}` in fact is), the generated class implements `IDisposable` interface and contains finally code (in this case `System.Threading.Monitor.Exit()` call) in the dispose code. The lock is released when the state machine comes to the end or when an exception occurs causing disposal of the object. – Pavel Mar 13 '15 at 22:59
  • @Pavel now you got me curious, what if I called GetEnumerator method and kept the reference of the enumerator, will it hold the lock for the entire life time of the enumerator? – Steve Mar 13 '15 at 23:06
  • @Steve, this is exactly what is going to happen: class LockTest { static object s = new object(); static IEnumerator rooted; static void Main(string[] args) { RootMyEnumerator(); var t = new Thread( () => Foo().MoveNext() ); t.Start(); t.Join(); //never reach this point } static void RootMyEnumerator() { rooted = Foo(); rooted.MoveNext(); } static IEnumerator Foo() { lock (s) { yield return 1; } } } – Pavel Mar 13 '15 at 23:50

0 Answers0