Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I detect a ThreadAbortException in a finally block? (.NET)

I have some critical logic in a finally block (with an empty try block), because I want to guarantee that the code gets executed even if the thread is aborted. However, I'd also like to detect the ThreadAbortException. I've found that wrapping my critical try/finally block in a try/catch does not catch the ThreadAbortException. Is there any way to detect it?

try {
    try { }
    finally {
        // critical logic
    }
} catch(Exception ex) {
    // ThreadAbortException is not caught here, but exceptions thrown
    // from within the critical logic are
}
like image 623
Chris Avatar asked Dec 09 '08 16:12

Chris


2 Answers

This is a curious problem.

The code you posted should work. It seems there's some kind of optimization going on that decides not to call your catch handler.

So, I wanted to detect the exception with this:

bool threadAborted = true;
try {
  try { }
  finally { /* critical code */ }
  threadAborted = false;
}
finally {
  Console.WriteLine("Thread aborted? {0}", threadAborted);
}
Console.WriteLine("Done");

(My actual code just slept in that critical code section, so I could be sure it would abort after that finally.)

It printed:

Thread aborted? False

Hmmm, strange indeed!

So I thought about doing a little bit more work there, to trick any "smart" optimizations:

bool threadAborted = true;
try {
  try { }
  finally { /* critical code */ }
  threadAborted = AmIEvil();
}
finally {
  Console.WriteLine("Thread aborted? {0}", threadAborted);
}
Console.WriteLine("Done");

Where AmIEvil is just:

[MethodImpl(MethodImplOptions.NoInlining)]
static bool AmIEvil() {
  return false;
}

Finally it printed:

Thread aborted? True

And there you have it. Use this in your code:

try {
  try { }
  finally { /* critical code */ }
  NoOp();
}
catch (Exception ex) {
  // ThreadAbortException is caught here now!
}

Where NoOp is just:

[MethodImpl(MethodImplOptions.NoInlining)]
static void NoOp() { }
like image 91
Jordão Avatar answered Nov 01 '22 11:11

Jordão


You can actually execute code in the catch statement just fine for a ThreadAbortException. The problem is that the exception will be rethrown once execution leaves the catch block.

If you want to actually stop the exception from continuing you can call Thread.ResetAbort(). This does require full trust though and unless you have a specific scenario, it's almost certainly the wrong thing to do.

ThreadAbortException

like image 31
JaredPar Avatar answered Nov 01 '22 11:11

JaredPar