如何正常卸载已运行线程的子AppDomain

我有一个加载子AppDomain的服务,然后启动一个在其中运行的线程。 它需要一个AppDomain,因为它动态生成并加载一些代码,我需要能够重新启动它而不会终止整个服务。

因此,在子AppDomain的事件循环中运行一个线程,它通过MarshalByRefObject传递给它的事件,MarshalByRefObject将东西粘在并发队列中。 我想停止并卸载子AppDomain并创建一个新的AppDomain。

我可以简单地在子AppDomain上调用Unload,但这将中止所有线程并抛出ThrearAbortException。 我怎样才能优雅地把它关掉? 如果我使用MarshalByRefObject在子AppDomain中设置一些静态标志,那么主进程如何能够等到它完成卸载?

我有一些示例代码,它显示了它的设置以及如何调用Unload来杀死它,我怎么能修改它以允许正常卸载并且永远不会有多个子AppDomains?

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 { ///  /// Calls to methods magically get transfered to the appdomain it was created in because it derives from MarshalByRefObject ///  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(); } } } } 

请尝试以下方法

 runnerThread.IsBackground = true; 

并且,是的,如果您没有先停止线程,则无法正常卸载AppDomain。

这种情况基本上与两个AppDomain是独立进程的情况相同,因此您需要使用某种forms的IPC。 一种选择是在请求循环停止时将事件句柄传递给子AppDomain。 循环可以在退出之前发出事件信号。 等待事件给循环一些时间来完成。 如果你超时,那么你可以做一个粗略的卸载。