Thursday, 5 April 2012

CLR vs JVM: Unhandled exception in Thread

There's something interesting that expands a bit this previous post. Since .Net 2.0, when we get an unhandled exception in any of our threads, the whole application is shutdown. This is something that changed from the .Net 1.0 times, and that I was not fully aware of. I think it makes sense, if an exception is unhandled the application should be shutdown, irrespective of whether it runs in the main thread or a separate one. If you want to avoid this, you have to wrap the code in a try catch, but watch out, the try-catch has to be inside the code that will be run in the separate thread, not surrounding the code that launches the thread. That's common sense, exceptions bubble up the stack until they are caught or they get to the top. Each thread has its own stack, so the try-catch needs to be inside the thread, not around it

What this means is that this exception won't be caught and your program will shutdown
class Searcher
{
 public void Search()
 {
  Console.WriteLine("Searching");
  Thread.Sleep(2000);
  throw new Exception("Search exception");
 }
}
class App
{
 public static void Main()
 {
  try{
   new Thread(new Searcher().Search).Start();
  }
  catch(Exception ex){
   Console.WriteLine("Exception: " + ex.Message + " caught by program");
  }
  
  Console.WriteLine("Press 'q' to quit");
  string st = null;
  do{
   st = Console.ReadLine();
  }while (st != "q");
 }
}
On the contrary, your exception here will be caught and your program won't shutdown.
class Searcher
{
 public void Search()
 {
  try{
   Console.WriteLine("Searching");
   Thread.Sleep(2000);
   throw new Exception("Search exception");
  }
  catch(Exception ex){
   Console.WriteLine("Exception: " + ex.Message + " caught by program");
  }
 }
}


class App
{
 public static void Main()
 {
  Console.WriteLine("Main Thread");
  
  new Thread(new Searcher().Search).Start();
  
  
  Console.WriteLine("Press 'q' to quit");
  string st = null;
  do{
   st = Console.ReadLine();
  }while (st != "q");
 }
}

We can easily write a helper method to wrap this in case the method we're going to launch in its own thread lacks the try-catch routine

class ThreadHelper
{
 public static void RunThreadWrappedInExceptionHandling(ThreadStart code, Action catchRoutine)
 {
  new Thread(() => {
   try{
    code();
   }
   catch(Exception ex){
    catchRoutine(ex);
   }
  }).Start();
 }
}

class Searcher
{
 public void Search()
 {
  Console.WriteLine("Searching");
  Thread.Sleep(2000);
  throw new Exception("Search exception");
 }
}

class App
{
 public static void Main()
 {
  Console.WriteLine("Main Thread");
  
  ThreadHelper.RunThreadWrappedInExceptionHandling(new Searcher().Search, 
   (ex) => Console.WriteLine("Exception while searching: " + ex.Message + ", try again")
  );

You can get the code here

There's a fundamental gotcha here. Imagine we're using third party code that in turn is creating its own threads, if they have not adopted measures like ours, there's nothing we can do to prevent an exception in their threads to shutdown our program... Well, I think this is pretty serious stuff, imagine you have and Asp.NEt application that is using some component that creates its own threads. Imagine that you have that application running in an Application Pool along with some other applications (well, at least in principle I always assign a different AppPool to each Application), one failure in that component would be crashing all those applications. Don't think so? check this article

It's very important to note here that the JVM behaves quite differently. As you can read here, an unhandled exception will end the thread were it was thrown, but not the whole program.

This short article explaining how the JVM handles exceptions makes a good read. And the same goes for this article for the CLR. In both cases an Exception Table is used to describe protected blocks and locate the catch-finally code to run if an exception happens (in the JVM there seems to be one table per method, in the CLR one table for the whole executable). It's very important to understand that exceptions do not affect performance unless they occur, I mean, wrapping your code in as many try-catch blocks as you judge necessary won't have any effects performancewise (the only cost it incurs is the addition of entries to that table) until those exceptions begin to happen. It's explained in several StackOverflow questions... This means that you should not be concerned about placing a try-catch inside a loop, the entry to the exception table is added once, not n times

According to msdn:Performance Tips and Tricks you can use try and catch without any performance problem until the real throw occurs.

No comments:

Post a Comment