Thread.Abort is a Sign of a Poorly Designed Program

Continuing the theme of Thead.Sleep is a sign of a poorly designed program, I’ve been meaning to provide similar detail on Thread.Abort and not just allude to it in other posts like ‘System.Threading.Thread.Suspend() is obsolete: ‘Thread.Suspend has been deprecated….

Many of the concepts I’ve discussed regarding Thread.Suspend also apply to Thread.Abort, and in much the same way that the ability to terminate a thread has existed for so long that the concept has remained ubiquitous when dealing with threads and it just keeps getting implemented without thought.  Thread.Abort is far more unsafe than Thread.Suspend; but, unfortunately Thread.Abort has yet to be deprecated.

Unlike Thread.Suspend, Thread.Abort stops your thread and it can’t continue afterwards.  In the same vein as Thread.Suspend, Thread.Abort doesn’t know anything about your thread, and if your thread isn’t in a try block that handles ThreadAbortException, it just stops it where it is, which may be in the middle of updating a complex invariant.  This means the thread can’t continue where the left off like Thread.Suspend and Thread.Resume and can never get that invariant out of that corrupt state (and nothing else can, it has no idea where that thread left off).

Thread.Abort isn’t a full-blown terminate; it does cause all finally blocks that it knows about to execute before your thread is stopped and won’t terminate your thread while it’s in a catch or finally block.

There’s several concepts that go along with Thread.Abort.  One I’ve already mentioned, the ThreadAbortException exception.  Catching ThreadAbortException is conceptually cooperative thread termination.  My issue with catching ThreadAbortException is that you’re essentially using exceptions for normal flow of logic; which I don’t agree with.  The other concept is critical regions.  You might think that wrapping critical code with Thread.BeginCritcalRegion and Thread.EndCriticalRegion will mean your thread won’t be aborted while it’s executing that code.  Unfortunately, the .NET Framework doesn’t really us Begin/EndCriticalRegion for anything.  But, that’s also not the intention, the intention is to signify to the runtime (currently only SQL Server vNext, I believe, uses that information) that should a Thread.Abort be called on that thread, or an unhandled exception occur, corruption has occurred and it should simply unload the thread’s AppDomain.

But, the concept of interrupting the thread in the middle of something is really why you should never use Thread.Abort.  It’s one thing to interrupt you own code, but Thread.Abort actually as the potential to interrupt lock statements and cause locks not to be unlocked.  As Joe Duffy points out, there’s a check when running code on the x86 that makes sure Thread.Abort can’t interrupt between a call to Monitor.Enter when it is adjacent to a protected region.  But, on current 64-bit JITs this check does not exist and a thread can be aborted between the call to Monitor.Enter and the start of the protected region.

Unfortunately, the x86 is not entirely immune.  In the C# compiler, when optimizations are turned off, it emits no-ops in various places.  I can’t really confirm why, but the prevalent theory is to allow the Visual Debugger to put breakpoints on source code that otherwise wouldn’t have corresponding IL. (like the start brace, for example).  Unfortunately there’s a bug in the generation of that IL that means Thread.Abort can cause locks not to be unreleased.

Eric Lippert recently provided some of the detail of the bug on his blog.  But, essentially, this is what the C# compiler generates for IL code for the lock statement:
            call void [mscorlib]System.Threading.Monitor::Enter(object)
Hole:       nop
StartTry:   nop
            ldstr “in lock”
            call void [mscorlib]System.Console::WriteLine(string)
            nop
            nop
            leave.s EndFinally
EndTry:     ldloc.0
            call void [mscorlib]System.Threading.Monitor::Exit(object)
            nop
            endfinally
EndFinally: nop
            ret
    .try StartTry to EntTry finally handler EndTry to EndFinally

Which is emitted (from both .NET 2.0 and .NET 3.5 Beta 2) for the compilation of the following:

            lock (locker)

            {

                Console.WriteLine(“in lock”);

            }


This means the lock is acquired (call to Monitor.Enter) and a nop (at Hole) is executed before the start of the protected region (try block).  This means there’s an instruction after the acquisition of the lock that isn’t in the try block.  It’s at that point if Thread.Abort were called, the finally block would never get executed and the lock would not be released.  Likely this would result in deadlocks because nothing can ever release that lock now.


If you never use Thread.Abort, this issue doesn’t affect you.  But, it really just provides another good reason why people keep saying you should never use Thread.Abort.


In ‘System.Threading.Thread.Suspend() is obsolete: ‘Thread.Suspend has been deprecated…. I provide an example of cooperatively terminating a thread, if you’re interested in terminating your thread without using Thread.Abort.


Like catching Exception, there is an instance when Thread.Abort can be safely used: when you’re terminating your application.  If you’re terminating your application and you know you have a foreground thread running and it’s not responding, Thread.Abort can safely be used to ensure your application terminates bcause you’re shutting down and not using any existing invariants or locks.

10 thoughts on “Thread.Abort is a Sign of a Poorly Designed Program”

  1. What if you come into a situation in which you don’t have a choice ?
    Assuming your application is holding threads vs outside 3rd party resources, like DB, algorithmic engine.
    What if the threads are blocking for too long time ? You can use a timer to find out, but what are you gonna do with the threads ?!

  2. If you *have* to use Thread.Abort, then it’s a sign of a poorly designed program. If it’s not your code then (i.e. it’s code out of your control) yes, you have no choice. I would recommend talking to the vendor to have the problem corrected.

    There’s very good solutions for blocking time-outs. You’d have to describe the blocking situation for me offer an example of this…

  3. @Rajeev. Second last paragraph, when I link to another post that describes how to cooperatively terminate a thread. The only way to reliable terminate a thread is to get it to do it itself.

  4. Strange because in our code we don’t use 3rd party and we don’t use Thread.Abort calls anywhere to end threads, yet we have to deal with catching the threadabort exception.

  5. @Eric. HttpResponse.End calls Thread.Abort, which may require dealing with ThreadAbortException.

    Other than that, you shouldn’t have to deal with it unless you explicitly call Thread.Abort or code that uses your code calls Thread.Abort. Where do you have to deal with ThreadAbortException?

  6. Abort() is similar to Ctrl-C in operating systems, not perfect but useful and necessary.

    When you design some multi-threaded framework, you don’t know what will be running in a thread. Even you can notify the thread to terminate ‘safely’, you never know if the termination is really ‘safe’ or even implemented by the users of your framework. You cannot control it!

    So the best solution is: notify the thread to terminate safely, but if failed (in a given time period or by other conditions), terminate it by Abort(). It’s better than without it, right?

  7. The only I can think of only 2 ways to abort a NamedPipeClientStream.Connect. Use a separate thread to perform the Connect. Call Thread.Abort when nothing connects to it. The second is to call Connect in a separate thread with a timeout value, in an infinite loop, but test for a “terminate thread” flag to break the loop and end the thread. However, this may be impractical. How would you handle the situation?

  8. I agree that Thread.Abort is a sign of terrible code, especially when it is called by the CLR in a completely-undocumented fashion. In any non-trivial multi-threaded project I have ever created, the CLR or framework code will randomly call Thread.Abort.

    It’s driving me crazy. What is Microsoft’s internal policy on calling Thread.Abort in their own library code, so that I can know which framework classes I need to rewrite myself to achieve true thread safety? Thanks.

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>