Thread.Abort() on a thread executing a Finally/Catch or .ctor block.

Issue: If a thread t is in some catch or finally or cctor block, calling t.Abort() from another thread does not have any effect on the thread. Here is the code to repro this.

 using System;using System.Threading;namespace ConsoleApplication2{class Program{static Thread t;[STAThread]static void Main(string[] args){Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);t = new Thread(ChildThread);t.Start();t.Join();}static void ChildThread(){try{throw new Exception();}catch (Exception){try{Console.WriteLine("going to sleep");Thread.Sleep(10000);Console.WriteLine("out of sleep");}catch (ThreadAbortException e){Console.WriteLine(e.ToString());}}}static void Console_CancelKeyPress(Object sender, ConsoleCancelEventArgs e){Console.WriteLine("aborting");if (t != null){t.Abort();t.Join();}}}}

Run the code and press CTRL+C to repro.

Club this issue with try\retry code in Abhinaba's blog and you have infinitly waiting call. May be this is the reason The Old New Thing advices against using retry indiscriminatly

Explaination that I got from the feature team:

Well, this is really interesting. Jeff's answer is a bit misleading; the actual behavior is more complex (and as the person who has to document it, I could wish it were more consistent).

(1) In the case of the catch block, the call to the Abort method does NOT block and the thread WILL abort as soon as the catch block completes. This is true even if no further code executes on the thread after the catch block.

(2) In the case of the finally block and the static constructor, the call to the Abort method appears to block until the finally block or static constructor completes! This is totally unexpected. If the thread doesn't execute any more code after the finally block or the static constructor, then ThreadAbortException is never thrown; but if the thread goes on executing long enough it WILL abort. (How long is "long enough"? Well, let's just say it's a race condition.)

Joe, can we say for sure that this is by design? I don't like the fact that the catch behaves differently from the finally and the static .ctor, and I REALLY don't like the Abort method blocking.

reply to this:

We should mention that Aborts called asynchronously on another thread might block, but I don’t know that we should document the exact behavior. Because there are situations where it won’t block, we do not want people to rely on blocking e.g. to signal that the thread has finished its abort.

But the more important (IMHO) thing to document is when abort requests are actually processed. Not processing the abort until after leaving catches, finallys, cctors, CERs, and unmanaged code is expected & fine. There are places we know of—e.g. Socket.Accept—which ends up blocking in an FCALL, which means we are unable to interrupt it. So this is an explanation of a bug that a user might reasonably hit.

What I don't like About this:

  1. As mentioned the call should not be blocking. This leaves the user waiting indefinitly. I have hit this bug making a webservice call and there was an IISREST on the server my call got stuck till there was a timeout at the client side and a Thread.Abort() on given thread was just waiting!!!
  2. There is no way to say Abort no matter what. So you may end up adding complex logic to have a clean exit. see my earlier blog.
  3. And to top that there is no documentation arround this. We would have been doomed if we were not in Microsoft. It was easy for us to just mail a discussion group and get a very quick response from the right people. Though they acknowledge this but I know its not an easy process to get the documentation updated after release. Just hope that they do it.