似乎在除主线程以外的线程执行代码时,finally块不会执行。那么有没有可能强制执行finally块呢?
环境:VS 2010,.Net Framework 4.0.3
class Program
{
static void Main(string[] args)
{
var h = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(
obj => TestProc(h));
h.WaitOne();
}
private static void TestProc(EventWaitHandle h)
{
try
{
Trace.WriteLine("Try");
h.Set();
}
catch(Exception)
{
Trace.WriteLine("Catch");
}
finally
{
Thread.Sleep(2000);
Trace.WriteLine("Finally");
}
}
}
更新:
我在MSDN中找到了有关该案例的提及和解释:
ThreadAbortException类 http://msdn.microsoft.com/zh-cn/library/system.threading.threadabortexception.aspx
当调用Abort方法来销毁线程时,公共语言运行时会抛出一个ThreadAbortException。ThreadAbortException是一种特殊的异常,可以捕获,但它会自动在catch块结束时重新引发。当引发此异常时,运行时将执行所有finally块后结束线程。因为线程可以在finally块中进行无限计算或调用Thread.ResetAbort取消中止,所以不能保证线程将结束。如果要等待已中止的线程结束,可以调用Thread.Join方法。Join是一个阻塞调用,只有在线程实际停止执行时才返回。
注意:
当公共语言运行时(CLR)在托管可执行文件的所有前台线程结束后停止后台线程时,不使用Thread.Abort。因此,无法使用ThreadAbortException检测CLR终止后台线程的情况。
前台线程与后台线程 http://msdn.microsoft.com/zh-cn/library/h339syd0.aspx
当运行时停止后台线程,因为进程正在关闭,线程中不会抛出异常。然而,当使用AppDomain.Unload方法卸载应用程序域时,前台线程和后台线程都会引发ThreadAbortException。
那么为什么在应用程序的结束(kill)之前CLR不使用AppDomain.Unload方法来卸载应用程序域呢? 因为http://msdn.microsoft.com/zh-cn/library/system.appdomain.unload.aspx:
结论:在某些情况下,我需要考虑我的代码是否将在后台或前台线程中执行?我的代码是否可能在应用程序主线程结束所有工作之前未完成?当线程调用Unload时,目标域将被标记为要卸载。专用线程尝试卸载域,并终止域中的所有线程。如果线程没有终止,例如因为它正在执行非托管代码或因为它正在执行finally块,则在一段时间后会在最初调用Unload的线程中引发CannotUnloadAppDomainException。如果无法终止的线程最终结束,则不会卸载目标域。因此,在.NET Framework版本2.0中,不能保证域已卸载,因为可能无法终止执行线程。