Is this a dangerous blocking scheme?

I have a counter written in C # that looks something like this:

try { ReadWriteLock.EnterReadLock(); yield return foo; yield return bar; yield return bash; } finally { if (ReadWriteLock.IsReadLockHeld) ReadWriteLock.ExitReadLock(); } 

I believe this could be a dangerous locking pattern, because ReadWriteLock will only be released if the enumeration is complete, otherwise the lock will remain hanging and will never be released, am I right? If so, what is the best way to deal with this?

+4
source share
3 answers

No, the finally block will always be executed, to a large extent, if someone does not pull the plug from the computer ( well, and a few more exceptions ).

 public static IEnumerable<int> GetNumbers() { try { Console.WriteLine("Start"); yield return 1; yield return 2; yield return 3; } finally { Console.WriteLine("Finish"); } } 

...

 foreach(int i in GetNumbers()) { Console.WriteLine(i); if(i == 2) break; } 

The above result will be

Start
1
2
Done

Note that in C # you write yield return , not just yield . But I guess it was just a typo.

+7
source

I think David answered the question that you intended to ask (about the listing aspect), but two more questions:

  • What happens if ReadWriteLock.EnterReadLock throws an exception?
  • What happens if ReadWriteLock.ExitReadLock exception?

In # 1, you call ReadWriteLock.ExitReadLock inappropriately. In # 2, you can hide the existing exception that was thrown (because finally clauses occur either because the mainline processing reached the end of the try block, or because the exception was thrown, in the latter case, you probably don’t want to hide the exception). Perhaps both of these things are unlikely in this particular case, but you asked about the template, and how the template has these problems.

+3
source

Finally, it will be executed in some way, but it can be unsafe for blocking. Compare the following methods:

 class Program { static IEnumerable<int> meth1() { try { Console.WriteLine("Enter"); yield return 1; yield return 2; yield return 3; } finally { Console.WriteLine("Exit"); } } static IEnumerable<int> meth2() { try { Console.WriteLine("Enter"); return new int[] { 1, 2, 3 }; } finally { Console.WriteLine("Exit"); } } static public void Main() { foreach (int i in meth1()) { Console.WriteLine("In"); } Console.WriteLine(); foreach (int i in meth2()) { Console.WriteLine("In"); } } } 

Exit:

 Enter In In In Exit Enter Exit In In In 

If your processing takes a lot of time (iteration), it is more reasonable to fill the collection first, and then process, but not give.

+2
source

Source: https://habr.com/ru/post/1311603/


All Articles