我有一個服務加載一個子AppDomain,然後啓動一個運行在其中的線程。它需要一個AppDomain,因爲它動態生成並加載一些代碼,我需要能夠重新啓動它而不會中止整個服務。如何正常卸載有線程運行的子AppDomain
所以有一個線程運行在子AppDomain的事件循環中,它通過一個MarshalByRefObject傳遞給它的事件傳遞給它,這個事件將一些東西放在併發隊列中。我想停止並卸載AppDomain子項並創建一個新的子項。
我可以簡單地在子AppDomain上調用Unload,但會中止所有線程並拋出ThrearAbortException。我如何優雅地關閉它?如果我使用MarshalByRefObject在子AppDomain中設置了一些靜態標誌,那麼主進程將如何等待完成卸載?
我有一些示例代碼,它顯示了它的設置以及如何調用Unload來殺死它,我怎麼修改這個以允許優雅的卸載並且永遠不會有多個子AppDomain?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;
using System.Security.Permissions;
using System.Reflection;
using System.Threading;
namespace TestAppDomains
{
/// <summary>
/// Calls to methods magically get transfered to the appdomain it was created in because it derives from MarshalByRefObject
/// </summary>
class MarshalProxy : MarshalByRefObject
{
public AppDomain GetProxyAppDomain()
{
return AppDomain.CurrentDomain;
}
public void SayHello()
{
Console.WriteLine("MarshalProxy in AD: {0}", AppDomain.CurrentDomain.FriendlyName);
}
public void RunLoop()
{
try
{
while (true)
{
Console.WriteLine("RunLoop {0} in {1}", DateTime.Now.ToLongTimeString(), AppDomain.CurrentDomain.FriendlyName);
Thread.Sleep(1000);
}
}
catch(Exception ex)
{
Console.WriteLine("You killed me! {0}", ex);
Thread.Sleep(200); //just to make sure the unload is really blocking until its done unloading
// if the sleep is set to 2000 then you will get a CannotUnloadAppDomainException, Error while unloading appdomain. (Exception from HRESULT: 0x80131015) thrown from the .Unload call
}
}
static int creationCount = 1;
public static MarshalProxy RunInNewthreadAndAppDomain()
{
// Create the AppDomain and MarshalByRefObject
var appDomainSetup = new AppDomainSetup()
{
ApplicationName = "Child AD",
ShadowCopyFiles = "false",
ApplicationBase = Environment.CurrentDirectory,
};
var childAppDomain = AppDomain.CreateDomain(
"Child AD " + creationCount++,
null,
appDomainSetup,
new PermissionSet(PermissionState.Unrestricted));
var proxy = (MarshalProxy)childAppDomain.CreateInstanceAndUnwrap(
typeof(MarshalProxy).Assembly.FullName,
typeof(MarshalProxy).FullName,
false,
BindingFlags.Public | BindingFlags.Instance,
null,
new object[] { },
null,
null);
Thread runnerThread = new Thread(proxy.RunLoop);
runnerThread.Name = "MarshalProxy RunLoop";
runnerThread.IsBackground = false;
runnerThread.Start();
return proxy;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("I am running in AD: {0}", AppDomain.CurrentDomain.FriendlyName);
var proxy = MarshalProxy.RunInNewthreadAndAppDomain();
proxy.SayHello();
while (true)
{
Console.WriteLine("Press enter to kill and restart proxy");
Console.WriteLine();
Console.ReadLine();
Console.WriteLine("Unloading");
AppDomain.Unload(proxy.GetProxyAppDomain());
Console.WriteLine("Done unloading");
proxy = MarshalProxy.RunInNewthreadAndAppDomain();
}
}
}
}
首先優雅地停止線程。 – 2011-03-31 00:35:18