C# 在ThreadAbortException上下文中,建议采用什么方法来防止资源泄漏?

C# 在ThreadAbortException上下文中,建议采用什么方法来防止资源泄漏?,c#,.net,idisposable,using,threadabortexception,C#,.net,Idisposable,Using,Threadabortexception,我正在努力提高一段代码的异常安全性,我意识到,即使使用构造用C#保护资源,引发的线程异常也可能导致不希望的资源泄漏。例如,考虑下面的代码(可以在一个单独的线程中运行)。 如果运行此代码的线程异常终止,那么我希望立即关闭filename引用的文件句柄。我是否可以在不使用try/finally块替换using构造的情况下执行此操作 我的假设是,ThreadAbortException随时都可能被提出,这意味着我应该注意语句之间发生的事情。虽然我可以使用try/finally块防止CreateWrit

我正在努力提高一段代码的异常安全性,我意识到,即使使用构造用C#
保护资源,引发的
线程异常
也可能导致不希望的资源泄漏。例如,考虑下面的代码(可以在一个单独的线程中运行)。 如果运行此代码的线程异常终止,那么我希望立即关闭
filename
引用的文件句柄。我是否可以在不使用try/finally块替换
using
构造的情况下执行此操作

我的假设是,
ThreadAbortException
随时都可能被提出,这意味着我应该注意语句之间发生的事情。虽然我可以使用try/finally块防止
CreateWriter
中的异常,但是
using
构造在计算括号中的表达式之前不会执行相同的操作,这意味着如果异常在
CreateWriter
返回后立即发生,则文件资源将保持打开状态


我知道终结器最终会释放文件句柄,但我想知道是否有一种确定性方法可以解决此问题,而不必在使用
CreateWriter
的每个位置捕获
ThreadAbortException

是的,防止此问题的确定性方法是不使用
Thread.Abort
。曾经向线程发出停止的信号,让它们优雅地终止
Thread.Abort
是一个很大的麻烦,放在API中只是为了让你绊倒


线程中止最常用于发生致命错误的情况,因此您的响应可能是让应用程序终止。如果您试图干净地停止自己的线程,请使用Thread.Join()。

这是一个折衷方案

  • 确保立即关闭所有资源,即使存在ThreadAbortException
  • 具有更简单的代码,但在调用Abort()时会临时泄漏资源
  • 我想你不是在呼叫Abort,只是想在其他人呼叫时找到一种安全的方法。如果您正在呼叫Abort,那么我建议您不要。这不是你会遇到的唯一问题。还有其他的

    #2是一个有效的选择,因为Abort()的调用者应该期望这样

    如果你想选择#1,那么我认为即使是一次简单的尝试/捕获也不会有帮助。如果ThreadAbortException可以在任何地方发生,那么它仍然可以在文件打开后(在file.OpenWrite()内部)以及将其分配给可以调用Dispose()的变量之前发生——您将遇到与在代码中使用相同的问题

    你需要像这样的语义学

      using (var handle = GetUnOpenedHandle()) {
            handle.Open(); // this can't involve assignment to any field of handle
      }
    
    我不确定这是否可行。

    在许多情况下(但肯定不是所有情况),您可以防止出现
    线程异常。NET BCL中的大多数关键代码都已经很好地实现了这一点。问题是很难做到正确。出于这个原因,大多数人建议避免线程中止,这是正确的。从2.0版开始,CLR使线程中止变得更容易容忍,并引入了一组新的API来帮助代码作者防范它们。深入了解所有这些是如何工作的

    我相信您对
    使用
    块的示例的关注是正确的。要使受约束的执行区域正常工作,带外(异步)异常必须在
    try
    块中发生。但是,由于
    使用
    展开的方式,表达式在
    try
    块之外求值。将其与
    lock
    块的扩展进行对比,后者从
    try
    块中计算表达式。无论如何,这是真的,这是专门为了防止这些例外情况而改变的

    所以问题是为什么使用
    块时没有对
    进行相同的更改。这是一个可以接受的省略,因为假设线程中止之后总是会终止AppDomain,这无论如何都会触发终结器


    所以是的。您的代码不能容忍带外(异步)异常。但是,比我聪明的人普遍认为不应该这样做。

    公平地说,MSDN也警告不要使用它。它是为了与backw兼容而维护的。
      using (var handle = GetUnOpenedHandle()) {
            handle.Open(); // this can't involve assignment to any field of handle
      }