Timeout Pattern - How bad is Thread.Abort really?
Potentially very bad.
The aborted thread could leave shared state corrupted, could leave asynchronous operations running, ...
See Joe Duffy's blog: "Managed code and asynchronous exception hardening".
Revisiting Thread.Abort() - is it safe?
Thread.Abort
is a lot safer than it used to be for the following reasons.
- The runtime will defer aborts while execution is in unmanaged code.
- The abort will allow
finally
blocks to execute.
However, there is still a problem with exactly when the ThreadAbortException
gets injected. Consider this code.
public class Example
{
private DateTime value = DateTime.MinValue;
public void DoSomething()
{
try
{
value = DateTime.UtcNow;
}
finally
{
}
}
}
If this code were running on a 32-bit platform the value
variable could be corrupted if Thread.Abort
was called and the ThreadAbortException
were injected in the middle of the write to value
. Since DateTime
is 8 bytes the write has to take place using more than one instruction.
It is possible to guard against this by placing critical code in a finally
block and by using Constrained Execution Regions, but it would be incredibly difficult to get right for all but the simplest types your define. And even then you cannot just put everything in a finally
block.
Aborting c# threads
Once a thread is created, is it always alive/live/there (unsure of
proper description) until aborted?
NO, it will be live until the execution of the method block is not completed. It's no more live once the execution completes.
If it's a non threadpool thread then it's over and become non-usable but if it's threadpool thread then it goes and sits back in pool. So that, it can be assigned a new request whenever comes in.
When a thread is aborted/stopped, it will only abort by throwing an
error?
Yes it will throw a ThreadAbortException
but why will you abort though?
If you mean to cancel it then try using BackGroundWorker
or System.Threading.Tasks.Task
instead. See Task Cancellation
C# Aborting a thread: Thread abort is not supported on this platform
Instead of tryng to forcefully abort the thread, you could set a flag to eventually exit the while
loop:
private bool _run = true;
public void refreshRoomList()
{
while (_run)
{
...
}
}
private void roomListBackButtonClick(object sender, RoutedEventArgs e)
{
_run = false;
}
What are the bad consequences of ThreadAbortException?
What are the other reasons not to use ThreadAbortExceptions in multithreaded control flow?
Thread.Abort can leave the thread in a very odd state, which can be impossible to handle cleanly.
From the docs for Thread.Abort:
if one thread calls Abort on another thread, the abort interrupts whatever code is running. There is also a chance that a static constructor could be aborted. In rare cases, this might prevent instances of that class from being created in that application domain. In the .NET Framework versions 1.0 and 1.1, there is a chance the thread could abort while a finally block is running, in which case the finally block is aborted.
If you're working in multithreaded code, this can be even more dangerous, as it can trigger a deadlock. This is also 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.
In general, it's far safer and cleaner to use the framework's cooperative cancellation model, and never call Thread.Abort
. Using CancellationToken
and CancellationTokenSource
allows you to design for proper cancellation in a way that's clean and where threads can properly handle their own cleanup.
Question about terminating a thread cleanly in .NET
Unfortunately there may not be a better option. It really depends on your specific scenario. The idea is to stop the thread gracefully at safe points. That is the crux of the reason why Thread.Abort
is not good; because it is not guaranteed to occur at safe points. By sprinkling the code with a stopping mechanism you are effectively manually defining the safe points. This is called cooperative cancellation. There are basically 4 broad mechanisms for doing this. You can choose the one that best fits your situation.
Poll a stopping flag
You have already mentioned this method. This a pretty common one. Make periodic checks of the flag at safe points in your algorithm and bail out when it gets signalled. The standard approach is to mark the variable volatile
. If that is not possible or inconvenient then you can use a lock
. Remember, you cannot mark a local variable as volatile
so if a lambda expression captures it through a closure, for example, then you would have to resort to a different method for creating the memory barrier that is required. There is not a whole lot else that needs to be said for this method.
Use the new cancellation mechanisms in the TPL
This is similar to polling a stopping flag except that it uses the new cancellation data structures in the TPL. It is still based on cooperative cancellation patterns. You need to get a CancellationToken
and the periodically check IsCancellationRequested
. To request cancellation you would call Cancel
on the CancellationTokenSource
that originally provided the token. There is a lot you can do with the new cancellation mechanisms. You can read more about here.
Use wait handles
This method can be useful if your worker thread requires waiting on an specific interval or for a signal during its normal operation. You can Set
a ManualResetEvent
, for example, to let the thread know it is time to stop. You can test the event using the WaitOne
function which returns a bool
indicating whether the event was signalled. The WaitOne
takes a parameter that specifies how much time to wait for the call to return if the event was not signaled in that amount of time. You can use this technique in place of Thread.Sleep
and get the stopping indication at the same time. It is also useful if there are other WaitHandle
instances that the thread may have to wait on. You can call WaitHandle.WaitAny
to wait on any event (including the stop event) all in one call. Using an event can be better than calling Thread.Interrupt
since you have more control over of the flow of the program (Thread.Interrupt
throws an exception so you would have to strategically place the try-catch
blocks to perform any necessary cleanup).
Specialized scenarios
There are several one-off scenarios that have very specialized stopping mechanisms. It is definitely outside the scope of this answer to enumerate them all (never mind that it would be nearly impossible). A good example of what I mean here is the Socket
class. If the thread is blocked on a call to Send
or Receive
then calling Close
will interrupt the socket on whatever blocking call it was in effectively unblocking it. I am sure there are several other areas in the BCL where similiar techniques can be used to unblock a thread.
Interrupt the thread via Thread.Interrupt
The advantage here is that it is simple and you do not have to focus on sprinkling your code with anything really. The disadvantage is that you have little control over where the safe points are in your algorithm. The reason is because Thread.Interrupt
works by injecting an exception inside one of the canned BCL blocking calls. These include Thread.Sleep
, WaitHandle.WaitOne
, Thread.Join
, etc. So you have to be wise about where you place them. However, most the time the algorithm dictates where they go and that is usually fine anyway especially if your algorithm spends most of its time in one of these blocking calls. If you algorithm does not use one of the blocking calls in the BCL then this method will not work for you. The theory here is that the ThreadInterruptException
is only generated from .NET waiting call so it is likely at a safe point. At the very least you know that the thread cannot be in unmanaged code or bail out of a critical section leaving a dangling lock in an acquired state. Despite this being less invasive than Thread.Abort
I still discourage its use because it is not obvious which calls respond to it and many developers will be unfamiliar with its nuances.
Related Topics
Using Image Control in Wpf to Display System.Drawing.Bitmap
How to Implement a Progress Bar Using the Mvvm Pattern
How to Post Using Httpclient Content Type = Application/X-Www-Form-Urlencoded
Best .Net Memory and Performance Profiler
Passing an Empty Array as Default Value of an Optional Parameter
Get the Icon for a Given Extension
Ef Code-First One-To-One Relationship: Multiplicity Is Not Valid in Role * in Relationship
How to Configure Swashbuckle to Ignore Property on Model
Data Binding in Wpf User Controls
C# - Winforms - Global Variables
Compare Two Datatables to Determine Rows in One But Not the Other
An Attribute Argument Must Be a Constant Expression, ...- Create an Attribute of Type Array
Best Way to Tackle Global Hotkey Processing in C#
How to Get the "Friendly" Os Version Name
Clearing Page Cache in ASP.NET
In C#, What Happens When You Call an Extension Method on a Null Object