And*_*dir 8 .net c# multithreading try-catch-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");
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新:
我在MSDN中找到了关于该案例的提及和解释:
ThreadAbortException类 http://msdn.microsoft.com/en-us/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/en-us/library/h339syd0.aspx
当运行时停止后台线程因为进程正在关闭时,线程中不会抛出异常.但是,当因为AppDomain.Unload方法卸载应用程序域而停止线程时,前台和后台线程中都会抛出ThreadAbortException.
那么为什么在应用程序结束时CLR不会使用AppDomain.Unload方法在主进程结束(kill)之前卸载应用程序域?因为http://msdn.microsoft.com/en-us/library/system.appdomain.unload.aspx:
当线程调用Unload时,目标域将标记为卸载.专用线程尝试卸载域,并且域中的所有线程都将中止.如果线程没有中止,例如因为它正在执行非托管代码,或者因为它正在执行finally块,那么在一段时间之后,在最初调用Unload的线程中抛出CannotUnloadAppDomainException.如果最终无法中止的线程结束,则不会卸载目标域.因此,在.NET Framework 2.0版域中不保证卸载,因为它可能无法终止执行线程.
结论:在某些情况下,我需要考虑我的代码是否会在后台或前台线程中执行?在应用程序主线程结束所有工作之前,我的代码是否可能无法完成?
Jon*_*eet 17
您的代码在后台线程中运行.设置时AutoResetEvent,您的单个前景线程终止(当您到达Main方法的末尾时)并且"立即"拆除该过程.
事实上,我认为你的finally块可能会开始执行,但是你要做的第一件事是睡两秒钟,这个过程会在它进入你的WriteLine呼叫之前退出.
如果您的Main方法仍在运行,或者任何其他前台线程使进程保持活动状态,您将看到您的finally块正常完成.这实际上并不是"最终在其他线程上"的问题 - 这是"只有前景线程才会保持活动状态"的问题.