DCSIMG
December 2012 - Posts - Bnaya Eshet

Bnaya Eshet

Disclaimer

December 2012 - Posts

My best Photos

My best Photos

this post is not a technical one.

I just put some of the best photos I took on a public Picasa folder

https://picasaweb.google.com/110804663513744011026/Best#

enjoy :)

Tpl Dataflow TOC

Tpl Dataflow TOC

TDF, Dataflow, TPL, Task, TOC, ISourceBlock, ITargetBlock

Will it crash my process

Will it crash my process

here is a short question,
it was taken from a real life bug that occurs at one of my customers.

will the following code crash the process?

Code Snippet
  1. List<object> items = new List<object>();
  2.  
  3. try
  4. {
  5.     Parallel.For(0, 10000000, t =>
  6.     {
  7.         items.Add("1");
  8.     });
  9.  
  10. }
  11. catch (AggregateException ex)
  12. {
  13. }

it is a non thread safe code that should throw an IndexOutOfRangeException.

but it wouldn't crash the process,
but what about the following code?

Code Snippet
  1. List<object> items = new List<object>();
  2.  
  3. try
  4. {
  5.     Parallel.For(0, 10000000, t =>
  6.     {
  7.         items.Add("1");
  8.     });
  9.  
  10. }
  11. catch (AggregateException ex)
  12. {
  13. }
  14.  
  15. items.Add("?");

Exception, .NET. Parallel. Thread, safe

despite the fact that the last addition is seem totally safe,
it will occasion crash the process.

so why does it happens?

the parallel code part was putting the list itself in a corrupted state,
which mean that further access will result in an exception.

the problem is that further access may be locate in a different code file, ant this will make this bug a very illusive one.

Async - Handling multiple Exceptions

Async - Handling multiple Exceptions

the SDP conference was ended a few week ago and I finally find a time to write some comments.

It was a very successful conference, the feedback and evaluations, of most sessions scored higher than 4.5, some well-over it. For example, one workshop had a perfect 5 / 5 score, and two other workshops scored 4.92 / 5 and 4.9 / 5. The highest score for a breakout session was 9.39 / 10, which is the highest score we’ve seen to date. my score was 4.90 / 5.

but this post isn't about scores, it is about fixing a sample that I was showing at the SDP about exception handling within the async / await context.

Parallel,Task, async, await, exception, whenall, parent, child, .NET 4.5

when you do use the great async / await syntax you may run into a problem while trying to handle multiple exception which was thrown from async operations (it can happens in cases like parent child relationship or when using WhenAll API).

by design the catch closure will handle the first exception and ignore all the other, you can read about it in here.

the following code will catch a single NullReferenceException or ArgumentException exception (the AggregateException will be ignored):

Code Snippet
  1.     try
  2.     {
  3.         await Task.Factory.StartNew(() =>
  4.             {
  5.                 Task.Factory.StartNew(() =>
  6.                     { throw new NullReferenceException(); },
  7.                         TaskCreationOptions.AttachedToParent);
  8.                 Task.Factory.StartNew(() =>
  9.                     { throw new ArgumentException(); },
  10.                         TaskCreationOptions.AttachedToParent);
  11.             });
  12.     }
  13.     catch (AggregateException ex)
  14.     {
  15.         // this catch will never be target
  16.     }
  17.     catch (Exception ex)
  18.     {
  19.         Console.WriteLine("## {0} ##", ex.GetType().Name);
  20.     }
  21. }

if you do want to catch the AggregateException you can use the following work around :

Code Snippet
  1. try
  2. {
  3.     Task t = Task.Factory.StartNew(() =>
  4.         {
  5.             Task.Factory.StartNew(() =>
  6.                 { throw new NullReferenceException(); },
  7.                     TaskCreationOptions.AttachedToParent);
  8.             Task.Factory.StartNew(() =>
  9.                 { throw new ArgumentException(); },
  10.                     TaskCreationOptions.AttachedToParent);
  11.         });
  12.     await t.ContinueWith(tsk => { if (tsk.Exception != null) throw tsk.Exception; });
  13. }
  14. catch (AggregateException ex)
  15. {
  16.     foreach (var exc in ex.Flatten().InnerExceptions)
  17.     {
  18.         Console.WriteLine(exc.GetType().Name);
  19.     }
  20. }

the difference is at line 12, I'm using a continuation that re-throw the AggregateException.

because this is a fairly common practice you may better wrap it within an extension method like the following one:

Code Snippet
  1. public static Task ThrowMultiple(this Task t)
  2. {
  3.     return t.ContinueWith(tsk => { if (tsk.Exception != null) throw tsk.Exception; });
  4. }
  5.  
  6. public static Task<T> ThrowMultiple<T>(this Task<T> t)
  7. {
  8.     return t.ContinueWith(tsk =>
  9.     {
  10.         if (tsk.Exception != null)
  11.             throw tsk.Exception;
  12.         return tsk.Result;
  13.     });
  14. }

you can use it as follow:

Code Snippet
  1. try
  2. {
  3.     await Task.Factory.StartNew(() =>
  4.         {
  5.             Task.Factory.StartNew(() =>
  6.                 { throw new NullReferenceException(); },
  7.                     TaskCreationOptions.AttachedToParent);
  8.             Task.Factory.StartNew(() =>
  9.                 { throw new ArgumentException(); },
  10.                     TaskCreationOptions.AttachedToParent);
  11.         }).ThrowMultiple();
  12. }
  13. catch (AggregateException ex)
  14. {
  15.     foreach (var exc in ex.Flatten().InnerExceptions)
  16.     {
  17.         Console.WriteLine(exc.GetType().Name);
  18.     }
  19. }

Summary

catching a single exception within an async method is a design decision,
but you may want to override this decision in some scenarios.

I hope that in a future release of .NET framework Microsoft consider to throw an AggregateException when the compiler will detect that the developer was adding an AggregateException catch block.

in the meantime you can use the extension methods.

you should not forget to catch a non AggregateException if you have any code before the await (this code will run synchronously).