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 メソッド