Why ThreadAbortException does not throw in catch block - c#

Suppose I have this code:
static void Main(string[] args)
{
var thread = new Thread(() =>
{
try
{
throw new InvalidOperationException();
}
catch (Exception)
{
Thread.Sleep(Timeout.Infinite);
}
});
thread.Start();
Thread.Sleep(TimeSpan.FromSeconds(1));
thread.Abort();
thread.Join();
}
It starts thread, then thread is going into sleep in catch block and after that we are trying abort thread.
Abort method have to raise ThreadAbortException. But in catch block it does not happen.
It's documented:
The thread that calls Abort might block if the thread that is being
aborted is in a protected region of code, such as a catch block,
finally block, or constrained execution region. If the thread that
calls Abort holds a lock that the aborted thread requires, a deadlock
can occur.
My question is why. Why is it working that way? Because in catch block we can raise any exceptions and all works like it have to.
UPDATE:
From the link by Jordão. Accepted because it's the most understandable clarification.
Constrained Execution Regions The .NET Framework 2.0 introduces
Constrained Execution Regions (CER), which impose restrictions both on
the runtime and on the developer. In a region of code marked as a CER,
the runtime is constrained from throwing certain asynchronous
exceptions that would prevent the region from executing in its
entirety. The developer is also constrained in the actions that can be
performed in the region. This creates a framework and an enforcement
mechanism for authoring reliable managed code, making it a key player
in the reliability story for the .NET Framework 2.0. For the runtime
to meet its burden, it makes two accommodations for CERs. First, the
runtime will delay thread aborts for code that is executing in a CER.
In other words, if a thread calls Thread.Abort to abort another thread
that is currently executing within a CER, the runtime will not abort
the target thread until execution has left the CER. Second, the
runtime will prepare CERs as soon as is possible to avoid
out-of-memory conditions. This means that the runtime will do
everything up front that it would normally do during the code region's
JIT compilation. It will also probe for a certain amount of free stack
space to help eliminate stack overflow exceptions. By doing this work
up front, the runtime can better avoid exceptions that might occur
within the region and prevent resources from being cleaned up
appropriately. To use CERs effectively, developers should avoid
certain actions that might result in asynchronous exceptions. The code
is constrained from performing certain actions, including things like
explicit allocations, boxing, virtual method calls (unless the target
of the virtual method call has already been prepared), method calls
through reflection, use of Monitor.Enter (or the lock keyword in C#
and SyncLock in Visual Basic®), isinst and castclass instructions on
COM objects, field access through transparent proxies, serialization,
and multidimensional array accesses. In short, CERs are a way to move
any runtime-induced failure point from your code to a time either
before the code runs (in the case of JIT compiling), or after the code
completes (for thread aborts). However, CERs really do constrain the
code you can write. Restrictions such as not allowing most allocations
or virtual method calls to unprepared targets are significant,
implying a high development cost to authoring them. This means CERs
aren't suited for large bodies of general-purpose code, and they
should instead be thought of as a technique to guarantee execution of
small regions of code.

The problem is that the thread you're attempting to abort is running inside a catch clause.
This will abort the thread:
static void Main(string[] args) {
var thread = new Thread(() => {
Thread.Sleep(Timeout.Infinite);
});
thread.Start();
Thread.Sleep(TimeSpan.FromSeconds(1));
thread.Abort();
thread.Join();
}
From this article:
In the .NET Framework 2.0, the CLR delays graceful thread aborts by default over CERs, finally blocks, catch blocks, static constructors, and unmanaged code.
This feature exists to keep the .NET framework more reliable in the face of certain asynchronous exceptions. Read the article I linked for the full story.
Your code basically misbehaves and a host would probably escalate that thread to a rude thread abort:
Rude thread aborts and rude application domain unloads are used by CLR hosts to ensure that runaway code can be kept in check. Of course, failure to run finalizers or non-CER finally blocks due to these actions presents the CLR host with new reliability problems, since there's a good chance these actions will leak the resources the back-out code was supposed to clean up.

This is by design, this was introduced in Fx 3 or 4.
You can look up the different versions form your own link and find different descriptions.
Allowing an AbortException inside those protected regions (as in Fx 1.x) can lead to very unpredictable situations and an unstable Process.
Note that Thread.Abort() is (was) generally dis-advised. And so is long-running code in any catch or finally clause.
Disallowing Abort to interrupt a catch clause addresses some of the issues with Abort. But it's still not perfect.

I suspect the point is that while you're in a catch or finally block, you're probably trying to clean up after yourself already. If an asynchronous exception can be triggered at that point, it's going to be really hard to do any sort of reliable cleanup.
Joe Duffy's blog post about asynchronous exceptions is likely to clarify this more than I can...

Related

.NET Core equivalent to Thread.Abort

Background
I have a Service abstraction. Each service has it own WorkItem. WorkItem able to start with some data. The service is limiting the excution time of WorkItem. Let's say that a single workitem can takes up to 60 seconds. After this, the Service should kill it.
This code migrated from the .NET Framework, I created a Thread object which run the Start(model) method. Then the code was something like:
Thread t = new Thread(workItem.Start, model);
t.start();
if (!t.Join(TimeSpan.FromSeconds(60)))
t.Abort();
The Thread.Abort was injecting an exception for the running thread, which lead it for immediately stop.
Now, I moved the code to dotnet core - as you may know, when you calling Thread.Abort() your getting the following message:
System.PlatformNotSupportedException: Thread abort is not supported on this platform.
at System.Threading.Thread.Abort()
at ...
The Goal
I want to limit the execution time of the WorkItem to specific amount of time. Note that this limitation should work also if you running code line like this:
Thread.Sleep(61000); // 61 seconds. should be stop after 60 seconds.
Progress
On the dotnet core world, it's seems like it's going to the Task related solution. So, I thought to use CancellationToken. But its seems like its impossible to watch the "Canceled" event and stop immediately. The examples I saw are using while (!canceled) loops, which cant stop long operations (like Thread.Sleep(1000000).
Question
How to do it right?
Update
I written this sample code:
public static bool ExecuteWithTimeLimit(TimeSpan timeSpan, Action codeBlock)
{
try
{
Task task = Task.Factory.StartNew(() => codeBlock());
if (!task.Wait(timeSpan))
{
// ABORT HERE!
Console.WriteLine("Time exceeded. Aborted!");
}
return task.IsCompleted;
}
catch (AggregateException ae)
{
throw ae.InnerExceptions[0];
}
}
And this Main file:
public static void Main(string[] args)
{
bool Completed = ExecuteWithTimeLimit(TimeSpan.FromMilliseconds(2000), () =>
{
Console.WriteLine("start");
Thread.Sleep(3000);
Console.WriteLine("end");
});
Console.WriteLine($"Completed={Completed}");
Console.ReadLine();
}
Expected: "end" wont be printed to the screen. Actual: "end" printed. Is there any alternative that can kill a Task?
Use thread.Interrupt(); instead of Abort() method.
Without aborting the only solution is to poll the cancellation request often enough so after all the while (!canceled) solution you mentioned.
The examples I saw are using while (!canceled) loops, which cant stop long operations (like Thread.Sleep(1000000).
This is just partially true. For example, this can be re-written like this to be responsive:
var timeout = TimeSpan.FromSeconds(60);
var stopwatch = new Stopwatch();
stopwatch.Start();
while (!cancelToken.IsCancellationRequested
&& stopwatch.ElapsedMilliseconds < timeout)
{
Thread.Sleep(10);
}
Of course, not every task can be easily re-written to poll the cancellation like this. If you are in a deep call chain it can be a pain to check the cancellation at every level. For that reason you can also use the CancellationToken.ThrowIfCancellationRequested method, which will throw an OperationCanceledException if there was a cancel request. I usually tend to not throwing an exception just for myself and using it for control flow but cancellation is one of the areas where it can be justified.
This is solution has of course some limitations compared to Abort:
You will not able to cancel 3rd party routines, which don't support cancellation and you cannot refactor them
The OperationCanceledException can be swallowed easily, whereas ThreadAbortException was always re-raised at the end of the catch blocks so a 3rd part library could be aborted by a good chance even if contained general catch blocks.
Update:
If you are confident/desperate enough you can use the ThreadEx.Abort method, which calls the Thread.AbortInternal by reflection. Though it is not guaranteed it will be a long-living solution in .NET Core.
Though I don't completely agree with making Thread.Abort obsolete as it was a good last-chance tool for shutting down routines on which you didn't have influence otherwise, I'm also at the side abortion must be avoided at all costs as it can have nasty side effects. If you are the author of the whole code base it can be always avoided.
Update 2:
It seems that AbortInternal has been removed since then. At least current .NET Core source does not contain such a method.
You could use Thread.Interrupt(), which causes a ThreadInterruptedException() in the worker thread. You can catch the exception with a try catch, and after that safely join the thread with the main thread to clean up the worker thread. This would look like this:
Thread t = new Thread(workItem.Start, model);
t.Start();
// do other stuff or wait
t.Interrupt();
t.Join();
And the function of the worker thread looks like this:
try
{
// stuff the worker thread needs to do
}
catch (Exception e)
{
// go in here when interrupted
}
Waiting can then be implemented like this
Thread t = new Thread(workItem.Start, model);
t.Start();
if (!t.Join(TimeSpan.FromSeconds(60)))
{
t.Interrupt();
t.Join();
}
This is a way to (kind off) kill threads, but it is more clean to do it with CancelationTokens. I say kind of here as the thread won't get interrupted until it is blocked by the OS or some other block. So if the thread never blocks the exception is never thrown, and thus the thread might complete without ever being interrupted.
Four years later, there is now an equivalent in net7 !
Non-cooperative abortion of code execution:
ControlledExecution
Be careful, this method might corrupt the process, see documentation.
You can read about why and how such a method came back to .NET here:
https://github.com/dotnet/runtime/issues/41291
https://github.com/dotnet/runtime/discussions/66480
From experience: When Thread.Abort was made obsolete, we looked around. Thread.Interrupt was not of use to us.
Our final decision - refactor code to run some code in its own process and then we can use Process.Kill.
Background on why we do rude interruptions on code: Our system is used in manufacturing process automation and when someone hits an emergency stop button, the standard is to stop whatever the code is doing within 100ms. Our code sends a request to shutdown to the process (which may be running a third-party driver that does not listen for aborts) and, if the process does not shut down in 50ms, we do a Process.Kill(true). Frankly, for an emergency stop, we do not care if the system gets corrupted - we're going to rebuild the processes, anyway. In extreme situations, we will reboot the computer if we can save a life.
We also recognize that this is an edge situation and most code never needs to do rude interruptions.
Thread.Abort() used to work when carefully Handled. There is no discussion: Thread.Abort() is a dangerous API that throws ThreadAbortException at any random point deep in the call stack. Nevertheless production logs show that when carefully implemented Thread.Abort() doesn’t provoke any crash nor state corruption.
CancellationToken is nowadays the safe way to implement cancelable operations. But it is not a replacement for Thread.Abort(): it only supports co-operative cancellation scenarios, where the cancellable processing is responsible for periodically checking if it has been cancelled.
if(cancelToken.IsCancellationRequested){
throw new TaskCancelledException();
}
Update
As suggested by #Theodor, Same result can be achieved by using
cancelToken.ThrowIfCancellationRequested();
This function implements the same logic as above
you can then handle the thrown exception as follows
try
{
await YourTask(cancellationToken);
}
catch (OperationCanceledException ex) // includes TaskCanceledException
{
MessageBox.Show("Your submission was canceled.");
}
Quoting an answer by a dotnet/runtime collaborator, in a recent GitHub issue.
Aborting threads without asking them is a very dangerous practice and has not been supported by design in modern .NET since .NET Core 1.0, which is why I will close this issue.
The safe alternative is to pass CancellationTokens around in your thread and mark the points that are OK to abort, yourself by calling CancellationToken.ThrowIfCancellationRequested. A nice rule of thumb is to call this method at the beginning of a loop, but perhaps not all loops, you have to make a balance; if you call it too often performance will decrease, and if you call it too rarely code might not stop immediately.
If the thread you want to abort is performing I/O, you can cancel it by switching to asynchronous methods and the async and await keywords and passing to them that CancellationToken.
But either way your code needs some refactoring.
(teo-tsirpanis, Feb 18, 2022)
So it seems that officially there is no equivalent API in .NET Core and later.
Just my two cents.
As per my readings from this book Parallel Programming and Concurrency with C# 10 and .NET 6
Generally, destroying a managed thread is considered an unsafe practice. That is why .NET 6 no longer supports the Thread.Abort method. In .NET Framework, calling Thread.Abort on a thread would raise a ThreadAbortedException exception and stop the thread from running. Aborting threads was not made available in .NET Core or any of the newer versions of .NET. If some code needs to be forcibly stopped, it is recommended that you run it in a separate process from your other code and use Process.Kill to terminate the other process.
You can use Cancellation Tokens in conjenction with Tasks as well.

Extensive use of ThreadAbortException

I'm working in a legacy project that has this exception handling code in many methods.
catch(ThreadAbortException e)
{
...
}
I don't see anywhere in the project Thread.Abort() or Thread.Interrupt() calls. Is it safe to delete all these ThreadAbortException handling or it is some other way that can be raised.
Well if answering specifically your question I would say that it would be better not to delete these exception handlers as it’s most likely that they were added by some developer trying to solve a problem. And I think there was a reason to add those handlers so if you just remove this code it can lead to appearing of some bugs again in the future.
Regarding the ThreadAbordException: I know for sure that it can be throwed not only with calling Thread.Abort() method when you are debugging (it might be a bug in VS, I’m not sure) and it forces your program to just crash silently. So depending on what’s inside of those handlers it could be possible that a developer was trying to solve such problem.
Also remember that you could be invoking methods of third-party libraries, web-services etc. in a separate thread, too. I’m not sure if they can throw such an exception but that’s a possible case to consider.
Official docs: "The exception that is thrown when a call is made to the Abort method." If you are completely sure there are no calls to Thread.Abort then you might as well erase those catch blocks.
EDIT: Be mindful that your code may be running in the context of an external app that may call Thread.Abort on your threads.
Not that it matters anyway as a ThreadAbortException can't really be handled as the CLR itself will rethrow it to actually kill the thread ASAP.
"Actually yes, a ThreadAbortException is special. Even if you handle it, it will be automatically re-thrown by the CLR at the end of the try/catch/finally. (As noted in the comments, it can be suppressed with ResetAbort but by that point the code smells like rotten fish.)"
- Read this question for more details: ThreadAbortException
Is the project running on a main thread and spinning up background worker threads? If the main thread exits while background threads are running, a ThreadAbortedException can occur on the background threads.
The catch statement could specifically handle this scenario, where no error actually occurred on the background thread, in a different manner than any other exception.

What's wrong with using Thread.Abort()

So I know that you shouldn't use
Thread.Abort()
But I've never been given a good explanation. Is there a performance penalty or some hidden gotcha?
I know you can't ignore/swallow the ThreadAbortException (which makes sense)
In addition to all of the other good answers here, let me add that there is no guarantee whatsoever that a call to Thread.Abort will actually abort the thread in question, ever. It is possible (though not particularly easy) to "harden" a thread against being aborted. If, for example, you are aborting a thread because you believe it to be running hostile code then the hostile code could be resisting its own destruction.
If you have a long-running operation involving code that you do not own that must be taken down cleanly, the correct way to do this is to put that code in its own process, not its own thread. (And preferably in a highly security-restricted appdomain in that process.) You can then cleanly kill the process.
In short, Thread.Abort is at best indicative of bad design, possibly unreliable, and extremely dangerous. It should be avoided at all costs; the only time you should ever even consider aborting a thread is in some sort of "emergency shutdown" code where you are attempting to tear down an appdomain as cleanly as possible.
Because if you know that the thread is in some safe state in which it can be aborted, surely you can arrange better communication and have the thread exit cleanly.
The thread could have taken a lock and be in the middle of changing some shared state, and the Thread.Abort will undo the lock and leave the shared state corrupted.
It's easier to hurt yourself. As others have stated it raises an exception in the code, which can occur at any point. This might be fine if you expect this and have coded in a way that elegantly handles this exception at any point but some people dont:
Monitor.Enter(obj);
// some code - if exception is raised here, then the lock isn't released
Monitor.Exit(obj)
IDisposable someCriticalResource = GetResource();
// some code - if exception is raised here, then the object isn't disposed
someCriticalResource.Dispose();
Additionally if you're working with many people on a team unless you have good code reviews you cannot guarantee the quality of the code you'll be working with. Hence it is a good idea to preach the gospal of "no Thread.Abort()" than it is to get people to remember to write code that is robust against exceptions occuring anywhere within that code.
In short.
Any IDisposable object may not be disposed. Any locked object may not be unlocked. Anything that must be 100% performed will never be done.
When you call Thread.Abort() on another thread a ThreadAbortException is injected in the flow of that thread. If you're lucky the code will handled this well and abort in a well defined state. The problem is that you have no way to figure out if you will be lucky in every case, so if you prefer safe over sorry calling Thread.Abort on other threads is not a good idea.
Thread.Abort stops your thread in an uncontrolled fashion.
thread.Abort will throw an exception, which will cause that your thread stops immediatly.
What is wrong with that: in most cases, you want to gracefully stop the operation that you're performing. For instance, if you are executing an ACID operation, you might want to complete the current operation before ending the thread, so that your system remains in a stable state.
Thread.Abort rises an exception in the target thread. Target thread in the meantime can be performing some critical operations and rising an exception can break your application state.

How do I use WaitHandles safely to prevent deadlocks?

Observe the following pseudo:
ManualResetEvent[] resetEvents = new ManualResetEvent[operations.Count];
for( int i = 0; i < operations.Count; i++ )
{
resetEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(timeConsumingOpHandler), resetEvents[i]);
}
WaitHandle.WaitAll(resetEvents);
In the case that an exception occurs inside one of the pooled threads, my ASP.NET WebApp is deadlocking. No exception information is being passed on the response stream.
I'm seeking suggestions to prevent this. A fixed timeout is acceptable.
Assume that the timeConsumingOpHandler Set()s the WaitHandle.
The entire timeConsumingOpHandler is wrapped in a try-catch-finally block where the WaitHandle is Set() during the finally section. None the less, deadlock occurs.
Are you certain you are in deadlock? In .NET 2.0, unhandled exceptions in the ThreadPool terminate the process.
You should not use the ThreadPool in ASP.NET applications. ASP.NET itself uses the ThreadPool to service requests, so you are competing for the same set of threads. If you must have asynchronous execution, use an asynchronous delegate.
Any blocking operation is a potential deadlock. There are ways that you can minimize or virtually eliminate the chance of a deadlock ever occurring (if you always make sure that your synchronized operations finish in a finite amount of time) but in the general case you can not just assume there's a safe way to prevent deadlocks.
A timeout goes a long way in ensuring that your application does not deadlock, but you'll then have stalling, and you'll need to recover from a timeout in an exceptional way. The same program flow doesn't apply any more.
If you have threads that throw exceptions check the Debug > Output window in Visual Studio it seems to always catch an exception even though the debugger fails to break when dealing with multiple threads.
It's looks like you're splitting up work into separate threads, to achieve parallelism. Why do you need this in a ASP.NET application?
You might want to look at a custom CLR host on MSDN that Joe Duffy developed to provide automatic deadlock detection.

To CurrentThread.Abort or not to CurrentThread.Abort

I've seen a number of examples that have a thread procedure that looks like this.
private void ThreadProc()
{
while (serviceStarted)
{
// do some work
Thread.Sleep(new TimeSpan(0, 0, 5));
}
Thread.CurrentThread.Abort();
}
Is the Abort() really necessary at the end?
There are number of arguments against calling Abort()
Once the procedure exited - it is expected it has already cleaned up after itself.
Calling Abort() throws an exception, which is generally more resource intensive than just exiting a procedure.
I'd like to read an explanation for why this is or isn't a good practice.
Calling Thread.Abort() does raise an exception, and if you're writing code that will be re-used (or part of a base library) it's difficult for other developers to handle ThreadAbortExcpetions.
It's explained in this article about Reliability Best Practices.
I've always heard that calling Thread.Join() is a better way to do it, if you can wait until the thread is completed processing.
I don't know if anyone thinks it's a good practice. It can cause deadlocks (because unmanaged resources aren't properly cleaned up when you throw an exception)
Here's another article about it, and other methods to deal with the issue.
Once the loop exits, the thread will terminate on its own. There is not need to abort the thread.
The CurrentThread.Abort is not only superfluous, but genuinely harmful since it raises a ThreadAbortException. If another thread attempts to Join() your service loop thread, it will have to handle an exception unnecessarily. Your best bet is just to delete the line CurrentThread.Abort().
Calling Abort() on one's own thread is safe, but apart from that it should generally be avoided because you can't be sure other threads will terminate gracefully. In many cases you don't need to abort the thread. Just let it finish and it will be reclaimed.
A thread will naturally self-terminate when it has no further work to do: when the logic it was executing completes.
Thread.Abort() causes a ThreadAbortException to be thrown on the current thread with the explicit purpose of rapidly terminating all execution on the thread. This is one of the special .NET exceptions which is "uncatchable": you can write a catch block but the exception will continue to be thrown after the catch block completes. This ensures there is no way an instruction to abort a thread can be stopped by subsequent user code.
Calling Thread.Abort() is generally seen as bad practice as there are more graceful ways to terminate the logic you are executing. Cancellation is better handled using a CancellationToken.
Interesting question. But I would advise against it since such a statement would prevent the method from being reused easily.

Categories