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.
Related
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.
I have some .NET4 code that needs to know if/when a network request times out.
Is the following code going to cause a new Thread to be added to the .NET ThreadPool each time a task runs, and then release it when it exits?
var wait = new Task(() =>
{
using (var pauseEvent = new ManualResetEvent(false))
pauseEvent.WaitOne(TimeSpan.FromMilliseconds(delay));
}).ContinueWith(action);
wait.Start()
https://stackoverflow.com/a/15096427/464603 suggests this approach would work, but have performance implications for the general system.
If so, how would you recommend handling a high number of request timeouts/s - probably 1000timeouts/s when bursting?
In Python I have previously used something like a tornado IOLoop to make sure this isn't heavy on the Kernel / ThreadPool.
I have some .NET4 code that needs to know if/when a network request times out.
The easiest way to do this is to use a timeout right at the API level, e.g., WebRequest.Timeout or CancellationTokenSource.CancelAfter. That way the operation itself will actually stop with an error when the timeout occurs. This is the proper way to do a timeout.
Doing a timed wait is quite different. (Your code does a timed wait). With a timed wait, it's only the wait that times out; the operation is still going, consuming system resources, and has no idea that it's supposed to stop.
If you must do a timed wait on a WaitHandle like ManualResetEvent, then you can use ThreadPool.RegisterWaitForSingleObject, which allows a thread pool thread to wait for 31 objects at a time instead of just one. However, I would consider this a last-ditch extreme solution, only acceptable if the code simply cannot be modified to use proper timeouts.
P.S. Microsoft.Bcl.Async adds async/await support for .NET 4.
P.P.S. Don't ever use StartNew or ContinueWith without explicitly specifying a scheduler. As I describe on my blog, it's dangerous.
First of all, adding Tasks to Thread Pool doesn't necessarily cause new Thread to be added to Thread Pool. When you add a new Task to Thread Pool it is added to internal queue. Existing Threads from Thread Pool take Tasks from this queue one by one and execute them. Thread Pool will start new Threads or stop them as it deems appropriate.
Adding Task with blocking logic inside will cause Threads from Thread Pool to block. It means that they won't be able to execute other Tasks from queue, which will lead to performance issues.
One way to add delay to some action is to use Task.Delay method which internally uses timers.
Task.Delay(delay).ContinueWith(action);
This will not block any Threads from Thread Pool. After specified delay, action will be added to Thread Pool and executed.
You may also directly use timers.
As someone suggested in comment, you may also use async methods. I believe the following code would be equivalent of your sample.
public async Task ExecuteActionAfterDelay()
{
await Task.Delay(3000);
action();
}
You might also want to look at this question Asynchronously wait for Task<T> to complete with timeout.
I'm running into a deadlock situation when calling StackExchange.Redis.
I don't know exactly what is going on, which is very frustrating, and I would appreciate any input that could help resolve or workaround this problem.
In case you have this problem too and don't want to read all this;
I suggest that you'll try setting PreserveAsyncOrder to false.
ConnectionMultiplexer connection = ...;
connection.PreserveAsyncOrder = false;
Doing so will probably resolve the kind of deadlock that this Q&A is about and could also improve performance.
Our setup
The code is run as either a Console application or as an Azure Worker Role.
It exposes a REST api using HttpMessageHandler so the entry point is async.
Some parts of the code have thread affinity (is owned by, and must be run by, a single thread).
Some parts of the code is async-only.
We are doing the sync-over-async and async-over-sync anti-patterns. (mixing await and Wait()/Result).
We're only using async methods when accessing Redis.
We're using StackExchange.Redis 1.0.450 for .NET 4.5.
Deadlock
When the application/service is started it runs normally for a while then all of a sudden (almost) all incoming requests stop functioning, they never produce a response. All those requests are deadlocked waiting for a call to Redis to complete.
Interestingly, once the deadlock occur, any call to Redis will hang but only if those calls are made from an incoming API request, which are run on the thread pool.
We are also making calls to Redis from low priority background threads, and these calls continue to function even after the deadlock occurred.
It seems as if a deadlock will only occur when calling into Redis on a thread pool thread. I no longer think this is due to the fact that those calls are made on a thread pool thread. Rather, it seems like any async Redis call without continuation, or with a sync safe continuation, will continue to work even after the deadlock situation has occurred. (See What I think happens below)
Related
StackExchange.Redis Deadlocking
Deadlock caused by mixing await and Task.Result (sync-over-async, like we do). But our code is run without synchronization context so that doesn't apply here, right?
How to safely mix sync and async code?
Yes, we shouldn't be doing that. But we do, and we'll have to continue doing so for a while. Lots of code that needs to be migrated into the async world.
Again, we don't have a synchronization context, so this should not be causing deadlocks, right?
Setting ConfigureAwait(false) before any await has no effect on this.
Timeout exception after async commands and Task.WhenAny awaits in StackExchange.Redis
This is the thread hijacking problem. What's the current situation on this? Could this be the problem here?
StackExchange.Redis async call hangs
From Marc's answer:
...mixing Wait and await is not a good idea. In addition to deadlocks, this is "sync over async" - an anti-pattern.
But he also says:
SE.Redis bypasses sync-context internally (normal for library code), so it shouldn't have the deadlock
So, from my understanding StackExchange.Redis should be agnostic to whether we're using the sync-over-async anti-pattern. It's just not recommended as it could be the cause of deadlocks in other code.
In this case, however, as far as I can tell, the deadlock is really inside StackExchange.Redis. Please correct me if I'm wrong.
Debug findings
I've found that the deadlock seems to have its source in ProcessAsyncCompletionQueue on line 124 of CompletionManager.cs.
Snippet of that code:
while (Interlocked.CompareExchange(ref activeAsyncWorkerThread, currentThread, 0) != 0)
{
// if we don't win the lock, check whether there is still work; if there is we
// need to retry to prevent a nasty race condition
lock(asyncCompletionQueue)
{
if (asyncCompletionQueue.Count == 0) return; // another thread drained it; can exit
}
Thread.Sleep(1);
}
I've found that during the deadlock; activeAsyncWorkerThread is one of our threads that is waiting for a Redis call to complete. (our thread = a thread pool thread running our code). So the loop above is deemed to continue forever.
Without knowing the details, this sure feels wrong; StackExchange.Redis is waiting for a thread that it thinks is the active async worker thread while it is in fact a thread that is quite the opposite of that.
I wonder if this is due to the thread hijacking problem (which I don't fully understand)?
What to do?
The main two question I'm trying to figure out:
Could mixing await and Wait()/Result be the cause of deadlocks even when running without synchronization context?
Are we running into a bug/limitation in StackExchange.Redis?
A possible fix?
From my debug findings it seems as the problem is that:
next.TryComplete(true);
...on line 162 in CompletionManager.cs could under some circumstances let the current thread (which is the active async worker thread) wander off and start processing other code, possibly causing a deadlock.
Without knowing the details and just thinking about this "fact", then it would seem logical to temporarily release the active async worker thread during the TryComplete invocation.
I guess that something like this could work:
// release the "active thread lock" while invoking the completion action
Interlocked.CompareExchange(ref activeAsyncWorkerThread, 0, currentThread);
try
{
next.TryComplete(true);
Interlocked.Increment(ref completedAsync);
}
finally
{
// try to re-take the "active thread lock" again
if (Interlocked.CompareExchange(ref activeAsyncWorkerThread, currentThread, 0) != 0)
{
break; // someone else took over
}
}
I guess my best hope is that Marc Gravell would read this and provide some feedback :-)
No synchronization context = The default synchronization context
I've written above that our code does not use a synchronization context. This is only partially true: The code is run as either a Console application or as an Azure Worker Role. In these environments SynchronizationContext.Current is null, which is why I wrote that we're running without synchronization context.
However, after reading It's All About the SynchronizationContext I've learned that this is not really the case:
By convention, if a thread’s current SynchronizationContext is null, then it implicitly has a default SynchronizationContext.
The default synchronization context should not be the cause of deadlocks though, as UI-based (WinForms, WPF) synchronization context could - because it does not imply thread affinity.
What I think happens
When a message is completed its completion source is checked for whether it is considered sync safe. If it is, the completion action is executed inline and everything is fine.
If it is not, the idea is to execute the completion action on a newly allocated thread pool thread. This too works just fine when ConnectionMultiplexer.PreserveAsyncOrder is false.
However, when ConnectionMultiplexer.PreserveAsyncOrder is true (the default value), then those thread pool threads will serialize their work using a completion queue and by ensuring that at most one of them is the active async worker thread at any time.
When a thread becomes the active async worker thread it will continue to be that until it have drained the completion queue.
The problem is that the completion action is not sync safe (from above), still it is executed on a thread that must not be blocked as that will prevent other non sync safe messages from being completed.
Notice that other messages that are being completed with a completion action that is sync safe will continue to work just fine, even though the active async worker thread is blocked.
My suggested "fix" (above) would not cause a deadlock in this way, it would however mess with the notion of preserving async completion order.
So maybe the conclusion to make here is that it is not safe to mix await with Result/Wait() when PreserveAsyncOrder is true, no matter whether we are running without synchronization context?
(At least until we can use .NET 4.6 and the new TaskCreationOptions.RunContinuationsAsynchronously, I suppose)
These are the workarounds I've found to this deadlock problem:
Workaround #1
By default StackExchange.Redis will ensure that commands are completed in the same order that result messages are received. This could cause a deadlock as described in this question.
Disable that behavior by setting PreserveAsyncOrder to false.
ConnectionMultiplexer connection = ...;
connection.PreserveAsyncOrder = false;
This will avoid deadlocks and could also improve performance.
I encourage anyone that run into to deadlock problems to try this workaround, since it's so clean and simple.
You'll loose the guarantee that async continuations are invoked in the same order as the underlying Redis operations are completed. However, I don't really see why that is something you would rely on.
Workaround #2
The deadlock occur when the active async worker thread in StackExchange.Redis completes a command and when the completion task is executed inline.
One can prevent a task from being executed inline by using a custom TaskScheduler and ensure that TryExecuteTaskInline returns false.
public class MyScheduler : TaskScheduler
{
public override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return false; // Never allow inlining.
}
// TODO: Rest of TaskScheduler implementation goes here...
}
Implementing a good task scheduler may be a complex task. There are, however, existing implementations in the ParallelExtensionExtras library (NuGet package) that you can use or draw inspiration from.
If your task scheduler would use its own threads (not from the thread pool), then it might be a good idea to allow inlining unless the current thread is from the thread pool. This will work because the active async worker thread in StackExchange.Redis is always a thread pool thread.
public override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
// Don't allow inlining on a thread pool thread.
return !Thread.CurrentThread.IsThreadPoolThread && this.TryExecuteTask(task);
}
Another idea would be to attach your scheduler to all of its threads, using thread-local storage.
private static ThreadLocal<TaskScheduler> __attachedScheduler
= new ThreadLocal<TaskScheduler>();
Ensure that this field is assigned when the thread starts running and cleared as it completes:
private void ThreadProc()
{
// Attach scheduler to thread
__attachedScheduler.Value = this;
try
{
// TODO: Actual thread proc goes here...
}
finally
{
// Detach scheduler from thread
__attachedScheduler.Value = null;
}
}
Then you can allow inlining of tasks as long as its done on a thread that is "owned" by the custom scheduler:
public override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
// Allow inlining on our own threads.
return __attachedScheduler.Value == this && this.TryExecuteTask(task);
}
I am guessing a lot based on the detailed information above and not knowing the source code you have in place. It sounds like you may be hitting some internal, and configurable, limits in .Net. You shouldn't be hitting those, so my guess is that you are not disposing of objects since they are floating between threads which won't allow you to use a using statement to cleanly handle their object lifetimes.
This details the limitations on HTTP requests. Similar to the old WCF issue when you didn't dispose of the connection and then all WCF connections would fail.
Max number of concurrent HttpWebRequests
This is more of a debugging aid, since I doubt you really are using all the TCP ports, but good info on how to find how many open ports you have and to where.
https://msdn.microsoft.com/en-us/library/aa560610(v=bts.20).aspx
I am using TPL Dataflow library to implement a producer consumer scenario. The processing involves a pipeline of tasks. Dataflow library aptly suits my use case.
But I want to know how do I efficiently implement this use case [details below].
I want to use TPL Dataflow in a server type setting.
By a server type setting I mean production of data stream takes place continuously [asynchronously] forever. Consumption task also runs forever and consumes all the data produced by a producer[asynchronusly].
Thus my blocks run forever
How do I model this scenario efficiently? Moreover how can I deal with exception handling as I cannot Wait() [Without a call to Wait() I would not be able to catch the exceptions thrown on a faulted block as far as my understanding goes].
Exceptions
I usually wrap the delegates with exception handling because as you said a block's exception is stored in the Completion task and moreover a faulted block stays faulted so you would need to replace it to move on.
var block = new TransfromBlock<string, int>(number =>
{
try
{
return int.Parse(number);
}
catch (Exception e)
{
Trace.WriteLine(e);
}
});
Capacity
Another important issue is capping. If some part of your workflow can't handle the load, it's input queue would simply grow infinitely. That could lead to a memory leak or OutOfMemoryExceptions. So it's important to make sure to limit all your blocks with the appropriate BoundedCapacity and decide what to do when that limit is reached ("throw" items, save to storage, etc.)
Parallelism
While the default value for BoundedCapacity is -1 (unbounded), the default value for MaxDegreeOfPrallelism is 1 (no parallelism). Most applications can easily benefit from parallelism so make sure to set an appropriate MaxDegreeOfPrallelism value. When a block's delegate is purely CPU-intensive MaxDegreeOfPrallelism shouldn't be much higher than the available cores. As it has less CPU and more I/O-intensive parts the MaxDegreeOfPrallelism can be increased.
Conclusion
Using TPL dataflow throughout the application's lifetime is really simple. Just make sure to enable configuration through the app.config and tweak according to actual results "in the field".
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...