How to gracefully unload a child AppDomain with threads running

I have a service that loads a child AppDomain and then starts a thread running in it. He needs an AppDomain because it dynamically generates and loads some code, and I need to restart it without killing the whole service.

So, there is a thread running in the event loop in the AppDomain child application, it passes the events passed to it through the MarshalByRefObject, which stores the material in a parallel queue. I want to stop and unload a child AppDomain and create a new one.

I can just call Unload on the child AppDomain, but this will interrupt all threads and throw a ThrearAbortException. How can I gracefully close it? If I set some static flag in a child AppDomain using MarshalByRefObject, then how can the main process wait for it to complete unloading?

I have sample code that shows how to configure it and how I can call Unload to kill it, how can I change this to allow graceful unloading and never have multiple child 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 { /// <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(); } } } } 
+6
c # concurrency marshalling appdomain
source share
2 answers

Try to execute

 runnerThread.IsBackground = true; 

And, yes, there is no graceful unloading of AppDomain unless you first stopped the threads.

+8
source share

The situation is essentially the same as if the two AppDomains were separate processes, so you need to use some form of IPC. One option is to pass the event descriptor to the child AppDomain when it requests a loop stop. The loop may signal an event before exiting. Wait for the event to complete the loop. If you time out, then you can perform rough unloading.

+2
source share

All Articles