The dangers of Thread.Abort

There have been a lot of blog posts about why calling Thread.Abort from one thread to abort another is a bad idea. If you’re still wondering if it actually is that bad, you’ll be convinced by the end of this blog post :).


The other day, I was investigating frequent hangs in our application on the production machine. The only clue was that the last logged exception was a ThreadAbortException. What made it interesting was that in some cases, the application continued to run fine after logging the exception.  As I continued to look at the log data, I realized that every time the application hung, the ThreadAbortException’s stack trace had a particular third party library’s method at the top of the stack. The conclusion was that the application hanged whenever the thread was aborted when executing the third party library’s code.


Reflector and half an hour later, the reason for hanging became clear. The third party code looked like this :-


void DoX()
{
Monitor.Enter(lockObj);
//Do some interesting stuff
Monitor.Exit(lockObj);
}

Now do you see why?  If the ThreadAbortException gets thrown after acquiring the lock but before releasing it, the lock gets orphaned and no other thread will be able to acquire it. Ever. The third party library is used heavily by our app, so any thread that calls DoX after the abort will hang forever.


OK, so let’s set it right then.


void DoX()
{
lock(lockObj)
{
//Do some interesting stuff
}
}

The compiler will emit a try/finally block and will call Monitor.Exit from the finally block. That should solve the problem, right?


Maybe.


The CLR guarantees that it won’t throw ThreadAbortExceptions when running finally blocks (and CERs and constructors), so once the finally block starts executing, we’re safe. But what about if there is (JIT compiler generated) code that is run after the try block but before the finally block?


Even assuming there is no such code, things can still fail.


void DoY()
{
using (StreamReader sr = new StreamReader("Test.txt"))
{}
}

If a ThreadAbortException is thrown after the StreamReader constructor runs, but before the constructed instance gets assigned to the local variable (sr), then sr won’t be disposed.


The bottom line is that it is really hard to write code that works properly in the face of ThreadAbortExceptions. And even if you somehow manage to write it, you can never be sure that all your external libraries are written to cope with it.


Moral of the story : Listen to all the good advice and don’t call Thread.Abort from another thread :)

One thought on “The dangers of Thread.Abort”

  1. sadhu… question off the topic.. any suggestion on a good antispyware to use ?! i tried StopZilla in a different PC and it was very effective, but my PC has a 64 bit Vista and stopzilla isn’t available for it.. any suggestions would be great..

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>