Thread.Join似乎错误地返回false

我使用Thread.Join(int millisecondsTimeout)来终止一些AppDomain

通常,我收到一条错误消息,指出AppDomain未在5秒内终止。 在单步执行调试器时,我发现AppDomain.Unload()调用在5秒内很容易终止,但Thread.Join返回false。

我哪里错了?

 var thread = new Thread( () => { try { AppDomain.Unload(someAppDomain); } catch (ArgumentNullException) { } catch (CannotUnloadAppDomainException exception) { // Some error message } }); thread.Start(); const int numSecondsWait = 5; if (!thread.Join(1000 * numSecondsWait)) { // Some error message about it not exiting in 5 seconds } 

编辑1

值得添加每个AppDomain的function。 每个AppDomain至少有一个Timer 。 代码大致如下所示(请记住,为了便于阅读,我已将这些类的大量数据合并为一个)。

 static void Main(string[] args) { _exceptionThrown = new EventWaitHandle(false, EventResetMode.AutoReset); _timer = new Timer(TickAction, null, 0, interval); try { _exceptionThrown.WaitOne(); } finally { _timer.Dispose(_timerWaitHandle); WaitHandle.WaitAll(_timerWaitHandle); } } 

实际上我知道“Main”线程会抛出一个ThreadAbortException ,跳转到finally语句并确保Timer队列在退出之前完全耗尽。

所有Timer都在tick方法中记录。 所以我可以确定计时器队列上没有任何内容, _timer.Dispose(_timerWaitHandle)立即返回。

无论是否这样做,我Unload的三个AppDomain的至少一个将无法在5秒内完成。

如果您想确保appdomains始终在5秒内卸载,您可以尝试测量它。 例如使用这样的东西:

 var stopwatch = System.Diagnostics.Stopwatch.StartNew(); AppDomain.Unload(someAppDomain); long elapsedMillis = stopwatch.ElapsedMilliseconds; System.Diagnostics.Trace.Writeline("Unload duration: " + elapsedMillis + " ms"); 

Visual Studio的Output窗口(或sysinternals的DebugView工具)应该显示它

解压缩的原因在MSDN Library的Unload()文章中有详细记载:

在.NET Framework 2.0版中,有一个专门用于卸载应用程序域的线程。 这提高了可靠性,尤其是在托管.NET Framework时。 当线程调用Unload时,目标域将标记为卸载。 专用线程尝试卸载域,并且域中的所有线程都将中止。 如果线程没有中止 ,例如因为它正在执行非托管代码,或者因为它正在执行finally块,那么在一段时间之后,在最初调用Unload的线程中抛出CannotUnloadAppDomainException。 如果最终无法中止的线程结束,则不会卸载目标域。 因此,在.NET Framework 2.0版域中不保证卸载,因为它可能无法终止执行线程。

域中的线程使用Abort方法终止,该方法在线程中抛出ThreadAbortException。 虽然线程应该立即终止,但它可以在finally子句中继续执行不可预测的时间量。

因此,您需要找出为什么您的程序在该appdomain中运行一个线程以及为什么它拒绝中止。 例如,当它被隐藏在非托管代码中时。 使用Debug + Windows + Threads查看它们。