multithreadingexception和Dispose。 为什么Dispose没有打电话?

‘using’语句保证对象将被称为Dispose方法。 在这个例子中,这没有发生。 终结者方法也没有调用。

为什么这一切? 当其他线程上的exception发生时,我如何更改代码以保证处理我的对象?

class Program { static void Main(string[] args) { Thread th1 = new Thread(ThreadOne); Thread th2 = new Thread(ThreadTwo); th1.Start(); th2.Start(); th1.Join(); th2.Join(); } static void ThreadOne() { using (LockedFolder lf = new LockedFolder(@"C:\SomeFodler")) { // some pay load Thread.Sleep(5000); } } static void ThreadTwo() { // some pay load Thread.Sleep(1000); throw new Exception("Unexpected exception"); } } public class LockedFolder : IDisposable { private const string FILENAME_LOCK = ".lock-file"; private bool bLocked = false; public string FullPath { private set; get; } public LockedFolder(string FullPath) { this.FullPath = FullPath; Lock(); } private void Lock() { // lock our folder Console.WriteLine("Lock " + FullPath); //CreateLockFile(Path + FILENAME_LOCK); bLocked = true; } private void UnLock() { if (!bLocked) { Console.WriteLine("Already UnLocked " + FullPath); return; // already unlocked } Console.WriteLine("UnLock " + FullPath); // unlock our folder //DeleteLockFile(Path + FILENAME_LOCK); bLocked = false; } #region IDisposable Members private bool disposed = false; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public void Dispose(bool disposing) { if (!disposed) { if (disposing) { // Free managed resources } // Free unmanaged resource UnLock(); } disposed = true; } ~LockedFolder() { Dispose(false); } #endregion } 

输出:

\ Visual Studio 2010 \ Projects \ ExceptionExample \ ExceptionExample \ bin \ Debug> ExceptionExample.exe

锁C:\ SomeFodler

未处理的exception:System.Exception:\ Visual Studio 2010 \ Projects \ ExceptionExample \ ExceptionExample \ Program.cs中的ExceptionExample.ProgramThread()的意外exception:系统上System.Threading.ThreadHelper.ThreadStart_Context(对象状态)的第36行。 System.Threading.ThreadHelper.ThreadStart()上的System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback回调,对象状态)中的Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback回调,Object状态,Boolean ignoreSyncCtx)

Outupt无一例外:

\ Visual Studio 2010 \ Projects \ ExceptionExample \ ExceptionExample \ bin \ Debug> ExceptionExample.exe Lock C:\ SomeFodler UnLock C:\ SomeFodler

未处理的exception强制CLR终止进程。 对于.NET 4.0,关闭行为略有不同,终结器将在报告exception后运行。 但不是早期版本。

您可以通过为AppDomain.CurrentDomain.UnhandledException编写事件处理程序来解决此默认行为。 记录或报告exception并调用Environment.Exit()。 这允许终结器线程运行并调用您的Unlock()方法。

不要依赖于此,有一些令人讨厌的例外,如StackOverflow或FEEE,无论如何都会终止这个过程。 那么有人绊倒电源线或使用Taskmgr.exe在头部拍摄你的过程

没有任何保证 ; 例如,拔出插头或终止过程将不会using 。 所有保证的是, 在正常执行 (包括大多数理智的例外)中,它将调用Dispose()

在您的情况下,您有一个未处理的线程exception; 这是一个过程杀手。 所有的赌注都是关闭的,因为你的过程现在已经病态并且正在被放下(并且出于它的痛苦)。

如果您希望代码行为,您必须确保您没有进程中断exception; 线程位于该列表顶部的未处理exception。 强烈建议try任何线程级代码。

原因是当您的进程由于未处理的exception而终止时,终结器不会运行。 有关详细信息,请参见此处 您可以强制让终结器运行,以便在另一个线程的未处理exception处理程序中正常关闭您的进程。 当发生未处理的exception时,.NET Framework的策略几乎没有做任何事情,因为不清楚进程处于哪种状态。 处理终结器可能是不明智的,因为应用程序状态可能已损坏,并且在最终确定期间也会发生exception,这也会终止终结器线程。 最终效果是只有一些终结器运行,其余的未经处理。 这些后续exception确实使得查找应用程序失败的根本原因变得更加困难。

你的,Alois Kraus

如果在BackgroundWorker上运行线程,则抛出的任何exception都将在工作线程中捕获,并将作为线程返回的对象的一部分返回。 因此,您无需担心exception转义。

这会产生另一个问题,即您无法在BackgroundWorker上调用Join ,但是您可以将一个Semaphore添加到worker类,并将计数器设置为0(已阻止):

  private Semaphore workerFinsished = new Semaphore(0, 1); 

运行工作后添加等待,

  public void Join() { workerFinished.WaitOne(); } 

并在您的工作人员代码中添加一个发布,您希望表明您已完成。

  workerFinished.Release() 

正如Marc所说,一旦你的应用程序有未处理的exception,所有的赌注都相当多。 为了澄清实际using是什么,它需要这样的代码:

 using(var myDisposableObject = GetDisposableObject()) { // Do stuff with myDisposableObject } 

并将其翻译成以下内容:

 MyDisposableObject myDisposableObject; try { myDisposableObject = GetDisposableObject(); // Do stuff with myDisposableObject } finally { if(myDisposableObject != null) { myDisposableObject.Dispose(); } } 

那么当您的应用程序遇到未处理的exception时会发生什么? 未处理的exception导致应用程序终止。 此终止(或任何意外终止)可以防止您的using语句中的finally块正确执行。

您应该始终处理exception,即使在您没有使用try块进行线程调用的情况下也是如此。 考虑挂钩到AppDomain.UnhandledException事件以清理资源,记录内容等等,然后再将应用程序咬掉。

编辑

刚刚注意到Hans发布了类似AppDomain.UnhandledException的内容,他是对的。 任何程序都是这种情况,意外终止会产生意外结果。 但是,在您的情况下,正如所建议的那样,不要依赖完整的应用程序执行来完成,尤其是使用文件资源。 相反,考虑编写您的流程以预测甚至预期先前的执行失败。 然后您的应用程序可以根据需要处理不完整的执行 您可以创建日志以跟踪流程中步骤的进度或标记,并在每次运行时对其进行评估以解决不正确的执行状态。

另外,作为另一个注释,您的类(即使考虑到它们只是样本的事实)也不是线程安全的……您不会保护您的共享资源。