如何优雅地卸载运行线程的子 AppDomain [英] How to gracefully unload a child AppDomain that has threads running
问题描述
我有一个服务,它加载一个子 AppDomain,然后启动一个在其中运行的线程.它需要一个 AppDomain,因为它会动态生成和加载一些代码,我需要能够在不终止整个服务的情况下重新启动它.
I have a service that loads a child AppDomain and then starts a thread running in it. It needs an AppDomain because it dynamically generates and loads some code and I need to be able to restart it without killing the whole service.
所以有一个线程在子 AppDomain 的事件循环中运行,它通过 MarshalByRefObject 获取传递给它的事件,该对象将内容粘贴在并发队列中.我想停止并卸载子 AppDomain 并创建一个新的.
So there is a thread running in an event loop in the child AppDomain, it gets events passed to it through a MarshalByRefObject that sticks stuff in a concurrent queue. I want to stop and unload the child AppDomain and create a new one.
我可以简单地在子 AppDomain 上调用 Unload,但这会中止所有线程并抛出 ThrearAbortException.我怎样才能优雅地关闭它?如果我使用 MarshalByRefObject 在子 AppDomain 中设置一些静态标志,那么主进程如何能够等到卸载完成?
I can simply call Unload on the child AppDomain, but that will abort all the threads and throw a ThrearAbortException. How can I gracefully shut it down? If I set some static flag in the child AppDomain using the MarshalByRefObject then how will the main process be able to wait until its done unloading?
我有一些示例代码显示了它的设置方式以及如何调用 Unload 来终止它,我该如何修改它以允许正常卸载并且永远不会有多个子 AppDomains?
I have some example code that kind of shows how its setup and how I can call Unload to kill it, how could I modify 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();
}
}
}
}
推荐答案
试试下面的
runnerThread.IsBackground = true;
而且,是的,如果您没有先停止线程,就不会优雅地卸载 AppDomain.
And, yeah, there is no graceful unloading of AppDomain if you didn't stop the threads first.
这篇关于如何优雅地卸载运行线程的子 AppDomain的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!