AppDomain.Unload
AppDomain.UnloadによるスレッドのAbortと、抹殺されるスレッドの最後の抵抗(finally)によってCannotUnloadAppDomainExceptionが発生するまで。
親アプリケーション
public void Test1() { string childPath = "(子アプリのパス)"; AppDomain domain = AppDomain.CreateDomain( "UserDomain1" ); Action thread = () => domain.ExecuteAssembly( childPath ); thread.BeginInvoke( null, null ); try { for ( int i = 0 ; i < 6 ; i++ ) { Console.WriteLine( "parent" ); System.Threading.Thread.Sleep( 1000 ); if ( i == 3 ) AppDomain.Unload( domain ); } } catch ( System.CannotUnloadAppDomainException ) { Console.WriteLine( "cannot!" ); } }
子アプリケーション
static void Main( string[] args ) { try { for ( int i = 0 ; i < 6 ; i++ ) { Console.WriteLine( "child" ); System.Threading.Thread.Sleep( 1000 ); } } catch ( System.Threading.ThreadAbortException ) { Console.WriteLine( "abort !!!" ); } finally { System.Threading.Thread.Sleep( 2000 ); //抵抗 Console.WriteLine( "finally end" ); } }
Unload(Abort)するも、finallyブロックが実行されるため結局タイムアウトしてしまい、CannotUnloadAppDomainExceptionが発生する。
解説
.NET Framework Version 2.0 では、アプリケーション ドメインをアンロードするための専用のスレッドが使用されます。このバージョンの .NET Framework がホストされた環境では、これによって信頼性が向上します。スレッドから Unload が呼び出されると、ターゲット ドメインがアンロードの対象としてマークされます。専用のスレッドによって、そのドメインのアンロードが試みられ、そのドメインのすべてのスレッドが中止されます。アンマネージ コードを実行中である、または、finally ブロックを実行中である、などの理由からスレッドを終了できなかった場合は、一定時間の経過後に、Unload の呼び出し元スレッドで CannotUnloadAppDomainException がスローされます。最終的にスレッドを終了できなかった場合、ターゲット ドメインはアンロードされません。このように、.NET Framework Version 2.0 では、実行中のスレッドを中止できない場合があるため、domain が確実にアンロードされるという保証はありません。
メモ :
一部のケースでは、Unload を呼び出した直後に CannotUnloadAppDomainException が発生する場合があります (ファイナライザから呼び出した場合など)。
domain 内のスレッドは、Abort メソッドを使って終了され、そのスレッドで ThreadAbortException がスローされます。スレッドはすぐに終了する必要がありますが、finally 句が実行されている間は継続される場合があります。この時間は予測できません。
AppDomain.Unload メソッド