c# - 在 .NET 中使用 Thread.Abort() 和处理 ThreadAbortException 是否安全?

标签 c# .net multithreading concurrency azure

我需要在 C# 中开发一个多线程 Azure 辅助角色 - 创建多个线程,向它们提供请求,每个请求可能需要很长时间来处理(不是我的代码 - 我将调用 COM 对象来完成实际工作)。

角色关闭后,我需要优雅地停止处理。我怎么做?看起来如果我只是调用 Thread.Abort() ,就会在线程中抛出 ThreadAbortException ,并且线程甚至可以使用 try-catch-finally 。 (或using)来清理资源。这看起来相当可靠。

令我困扰的是,我的经验主要是 C++,不可能优雅地中止非托管应用程序中的线程 - 它只会停止而不进行任何进一步的处理,这可能会使数据处于不一致的状态。因此,我有点偏执,担心如果我为繁忙的线程调用 Thread.Abort() ,是否会发生类似的情况。

Thread.Abort()与处理ThreadAbortException一起使用是否安全?如果我这样做,我应该注意什么?

最佳答案

Is using Thread.Abort() and handling ThreadAbortException in .NET safe practice?

TL;DR 版本:不,不是。

通常,当所有类型不变量(无论是否明确声明)实际上都为真时,您就是安全的。然而,许多方法会在运行时打破这些不变量,只有当它们最终再次为真时才能达到新的状态。如果线程在保持不变量的状态下处于空闲状态,那么您会没事,但在这种情况下,最好使用事件之类的东西来通知线程正常退出(即您不需要中止)。

在这样的不变量不真实的情况下,线程中抛出带外异常1,即。无效,状态是问题开始的地方。这些问题包括但当然不限于相互不一致的字段和属性值(处于无效状态的数据结构)、未退出的锁以及未触发表示“发生更改”的事件。

在许多情况下,可以在清理代码中处理这些问题(例如 finally block ),但是然后考虑当 out-of- 时会发生什么带异常发生在清理代码中?这导致了清理代码的清理代码。但是该代码本身很容易受到攻击,因此您需要清理代码来清理代码......它永远不会结束!

有一些解决方案,但它们不容易设计(并且往往会影响您的整个设计),并且更难以测试 - 如何重新创建所有案例(想想组合爆炸)。两种可能的路线是:

  1. 处理状态副本,更新副本,然后以原子方式将当前状态交换为新状态。如果存在带外异常,则原始状态将保留(并且终结器可以清理临时状态)。

    这很像数据库事务的功能(尽管 RDBMS 使用锁和事务日志文件)。

    它也类似于 C++ 社区响应 paper questioning if exceptions could ever be safe 开发的实现“强异常保证”的方法。 (C++ 当然没有 GC/finaliser 队列来清理丢弃的对象)。请参阅赫伯·萨特斯 "Guru of the Week #8: CHALLENGE EDITION: Exception Safety"寻求解决方案。

    实际上,这很难实现,除非您的状态可以封装在单个引用中。

  2. 查看"Constrained Execution Regions" ,但不限制您在这些情况下可以执行的操作。 (MSDN 杂志有一个来自 .NET 2 测试版2introductory article(主题介绍,不是入门级别)。

在实践中,如果您必须这样做,那么使用方法 #2 来管理方法 #1 下的状态更改可能是最好的方法,但是正确使用它,然后验证它是否正确(并保持正确性)是很难

总结:这有点像优化:规则 1:不要这样做;规则 2(仅限专家):除非别无选择,否则不要这样做。

<小时/>

1 ThreadAbortException 并不是唯一的此类异常。

2因此细节可能已更改。

关于c# - 在 .NET 中使用 Thread.Abort() 和处理 ThreadAbortException 是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6382997/

相关文章:

c++ - 我可以从不同的线程访问 COM 对象的接口(interface)吗?

c# - 相当于通过变量名来引用控件?

c++ - 应该如何从回调函数更新/返回值?

Python 共享库

.net - 紧凑型框架定位

c# - 如何停止应用程序?

c# - .NET 中的线程中止

C# - 自定义 GUI 设计

c# - LINQ 运算符在泛型方法内部使用时不支持任何成员

c# - 没有换行符的文本文件中是否有最大行长?