c# - 为什么 ThreadAbortException 不抛出 catch block

标签 c# multithreading try-catch

假设我有这段代码:

    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();
    }

它启动线程,然后线程在 catch block 中进入休眠状态,之后我们尝试中止线程。

中止方法必须引发 ThreadAbortException。但是在 catch block 中它不会发生。 这是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.

我的问题是为什么。为什么会这样?因为在 catch block 中,我们可以引发任何异常,并且所有工作都必须如此。

更新: 来自link乔丹。接受是因为这是最容易理解的说明。

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.

最佳答案

问题是您试图中止的线程正在 catch 子句中运行。

这将中止线程:

static void Main(string[] args) {
  var thread = new Thread(() => {
    Thread.Sleep(Timeout.Infinite);
  });
  thread.Start();

  Thread.Sleep(TimeSpan.FromSeconds(1));

  thread.Abort();
  thread.Join();
}

来自 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.

此功能的存在是为了让 .NET 框架在面对某些异步异常时更加可靠。阅读我链接的文章以获取完整故事。

您的代码基本上行为不当,主机可能会将该线程升级为粗鲁的线程中止:

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.

关于c# - 为什么 ThreadAbortException 不抛出 catch block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7634797/

相关文章:

c# - 在哪里存储将在我的应用程序中使用的常量对象

c++ - std::thread 导致应用程序中止并出现错误 R6010

python:处理变量锁定的优雅方法?

R trycatch() 与 err 和 warn 处理程序一起使用,但 Shiny 仍然崩溃?

c# - UWP-如何通过右键单击或右击而没有选择Listviewitem来获取ListViewItem值?

c# - 自动展开PropertyGrid中的一些属性

c# - WebApi - 从 Uri 和 Body 绑定(bind)

java - 用于同步的 CyclicBarrier 与 CountDownLatch

java - try catch 数组吗?

java - 如何在循环中创建 try block ?