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
catchclause.This will abort the thread:
From this article:
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: