88bifa手机版[转]C#综合揭秘——细说进度、应用程序域与上下文之间的涉嫌

Posted by

 
 在当前的花色开荒中,分布式开拓已经日趋改为主流。一个类型只要未有运用遍及式架构,都倒霉意思跟别人说那是一个完全的种类。那句话尽管有一点偏激,不过随着大家对功用的渴求在压实,以至产品必要升高客户体验。独有在软件项目标效能和经验做到高水平,才得以得到客商和市集。

引言

   对于.NET项目,大家应用超多的分布式结构有Webservice,.Net
remoting,MSMQ,WCF,WebAPI等等,大家在利用这个框架的时候,从那些布满式框架中拿走了很好的顾客体验。在.NET项目中,分布式架构对项目标成本也会有不小的功能升高。

正文首要是介绍进度(Process)、应用程序域(AppDomain)、.NET上下文(Context)的概念与操作。
即便如此在相符的开垦在那之中那三者并临时用,但熟谙三者的涉及,深远理解其功效,对增加系统的性质有惊人的帮忙。
在本篇最后的生机勃勃节当中校会介绍到三者与线程之间的涉嫌,希望对三十二线程开辟人士能提供一定的协助。
因为日子仓促,文中有不当的地点敬请点评。

 
 很四个人会问,那些分布式框架的底层原理是怎样呢?可能何人也不敢轻言几句就可以描述实现,在此个博文系列中,就是轻松的描述一下那个分布式结构的尾部达成原理。

 

 
 本文重要教学对象在应用程序域中的传递。主要讲解使用程序域的有的主导目的,对于利用程序域的操作现身的比很少,所以在这里边给出的是程序集的豆蔻年华部分基本操作。如有美中不足,还望多多指正。

 

一.AppDomain解析:

   
 AppDomain在广大场地都以被翻译为“应用程序域”,在本文中也将使用那生机勃勃翻译。对于.NET的开采者,对于CLRubicon应该是最熟识然则了,CLPRADO相近于java的JVM。在CL瑞鹰中,AppDomain规定了代码的推行范围,提供了错误隔断的品位,提供了三个康宁隔开分离度,而且存有协调的能源。AppDomain的切切实时间效益果,好似下图:

  88bifa手机版 1

目录

   1.AppDomain概述:

     
AppDomain近似与系统的经过,进度是有操作系统实行创办,AppDomain是由CL路虎极光进行创办。五个加以的AppDomain必需驻留在三个操作系统的长河中,而多个加以的进程能够过夜多个AppDomain。犹如下图:

   88bifa手机版 2

     
如上航海用教室所示,一个目标正好存放在一个AppDomain种,值也同等。一个AppDomain中的对象引用必需是援引同风华正茂AppDomain中的对象,AppDomain的作为就就像有所和睦个人的地点空间。尽管七个AppDomain要求运用一个体系,必需为每一个AppDomain分别开首化和抽成贰次品种。必得为顺序用到花色的AppDomain分别加载和早先化二回品种的措施和次序集。进度种的逐意气风发AppDomain要保险项目标不如拷贝。对于项指标静态子类,种种AppDomain都有其和好的民用别本。

     AppDomain的能源好似图:

88bifa手机版 3

     
对于应用AppDomain的能源被加载,平昔在内部存储器中,卸载AppDomain财富是独一无二卸载模块可能程序集的路线,卸载AppDomain财富也是回笼类型静态字段所占内部存款和储蓄器的并世无双方法。

   
 在上面提到过操作系统的线程与AppDomain肖似,在CLLacrosse中定义了System.Threading.Thread,在AppDomain中表示为可调解的实体,在那地提议一个新的定义,那正是“软线程”和“硬线程”,看名就会猜到其意义,操作系统的线程被誉为“硬线程”,CL智跑中的System.Threading.Thread被誉为“软线程”。二个CLWrangler软线程对象驻留在二个分明的AppDomain中;一个加以的AppDomain也许有多少个软线程对象。在当下的CL凯雷德中,对于给定的AppDomain,硬线程至多有一个软线程对象属于她,假设三个硬线程运转在多少个AppDomain中,种种AppDomain都会有八个显眼的软线程对象属于该线程。当给定的硬线程步向AppDomain后,就能够拿走平等的软线程对象。

大器晚成、进度的概念与效果

   2.AppDomain主题对象拆解分析:

   
 下面介绍了一些AppDomain的基本概念,接下去大家来回顾领会一下AppDomain的相关操作和中坚指标。在.NET种能够透过System.AppDomain类型访谈AppDomain。在那地我们具体理解一下System.AppDomain类型的主意和品质。对于此类的证实:  

   (1).CurrentDomain:获取当前Thread 的当下选择程序域。

public static AppDomain CurrentDomain
    {
      get
      {
        return Thread.GetDomain();
      }
    }

   
由上述代码可知,该属性为二个静态属性,並且唯有一个只读属性。该属性只是简短地提取存款和储蓄在硬线程的TLS(线程当地存款和储蓄区)中的AppDomain援用。你能够在Thread.CurrentThread属性中,从硬线程的TLS中领取当前的软线程对象。 

   (2).GetData():为钦点名称获取存款和储蓄在当下利用程序域中的值。

[SecuritySafeCritical]
    public object GetData(string name)
    {
      if (name == null)
        throw new ArgumentNullException("name");
      switch (AppDomainSetup.Locate(name))
      {
        case -1:
          if (name.Equals(AppDomainSetup.LoaderOptimizationKey))
            return (object) this.FusionStore.LoaderOptimization;
          object syncRoot = ((ICollection) this.LocalStore).SyncRoot;
          bool lockTaken = false;
          object[] objArray;
          try
          {
            Monitor.Enter(syncRoot, ref lockTaken);
            this.LocalStore.TryGetValue(name, out objArray);
          }
          finally
          {
            if (lockTaken)
              Monitor.Exit(syncRoot);
          }
          if (objArray == null)
            return (object) null;
          if (objArray[1] != null)
            ((IPermission) objArray[1]).Demand();
          return objArray[0];
        case 0:
          return (object) this.FusionStore.ApplicationBase;
        case 1:
          return (object) this.FusionStore.ConfigurationFile;
        case 2:
          return (object) this.FusionStore.DynamicBase;
        case 3:
          return (object) this.FusionStore.DeveloperPath;
        case 4:
          return (object) this.FusionStore.ApplicationName;
        case 5:
          return (object) this.FusionStore.PrivateBinPath;
        case 6:
          return (object) this.FusionStore.PrivateBinPathProbe;
        case 7:
          return (object) this.FusionStore.ShadowCopyDirectories;
        case 8:
          return (object) this.FusionStore.ShadowCopyFiles;
        case 9:
          return (object) this.FusionStore.CachePath;
        case 10:
          return (object) this.FusionStore.LicenseFile;
        case 11:
          return (object) (bool) (this.FusionStore.DisallowPublisherPolicy ? 1 : 0);
        case 12:
          return (object) (bool) (this.FusionStore.DisallowCodeDownload ? 1 : 0);
        case 13:
          return (object) (bool) (this.FusionStore.DisallowBindingRedirects ? 1 : 0);
        case 14:
          return (object) (bool) (this.FusionStore.DisallowApplicationBaseProbing ? 1 : 0);
        case 15:
          return (object) this.FusionStore.GetConfigurationBytes();
        default:
          return (object) null;
      }
    }

 
 每一个AppDomain有和好的境况属性集,能够透过SetData和GetData方法访谈,在此给出了GetData()方法的源码。该方法采用一个string参数,预约义应用程序域属性的称号,或已定义的运用程序域属性的称呼。重临四个属性的值,或
null(固然属性不设有)。AppDomainSetup类为五个密闭类,表示能够拉长到System.AppDomain的实例的程序集绑定消息。

 
 (3).CreateDomain:使用钦定的称号、证据和应用程序域设置新闻创制新的利用程序域。

[SecuritySafeCritical]
    [SecurityPermission(SecurityAction.Demand, ControlAppDomain = true)]
    public static AppDomain CreateDomain(string friendlyName, Evidence securityInfo, AppDomainSetup info)
    {
      return AppDomain.InternalCreateDomain(friendlyName, securityInfo, info);
    }

 
 该措施存在多少个重载,接收八个参数,域的友善名称。friendlyName:此友好名称可在顾客分界面中显得以标记域;securityInfo:分明代码标志的凭据,该代码在接受程序域中运营。传递
null
以应用当前使用程序域的凭证。info:包括应用程序域开首化音讯的对象。该格局重回三个新创制的施用程序域。

 
 (4).ExecuteAssembly():使用钦点的凭据和实参推行内定文件中蕴含的次序集。

 [Obsolete("Methods which use evidence to sandbox are obsolete and will be removed in a future release of the .NET Framework. Please use an overload of ExecuteAssembly which does not take an Evidence parameter. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
    public int ExecuteAssembly(string assemblyFile, Evidence assemblySecurity, string[] args)
    {
      if (assemblySecurity != null && !this.IsLegacyCasPolicyEnabled)
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_RequiresCasPolicyImplicit"));
      RuntimeAssembly assembly = (RuntimeAssembly) Assembly.LoadFrom(assemblyFile, assemblySecurity);
      if (args == null)
        args = new string[0];
      return this.nExecuteAssembly(assembly, args);
    }

 
 当创造三个AppDomain后,能够动用风度翩翩多级技艺强制它加载和推行代码,能够选择ExecuteAssembly方法。该方法将对象AppDomain加载到程序集中,而且施行其主入口点。在父AppDomain种,ExecuteAssembly方法不会加载也许起头化钦点的顺序集。ExecuteAssembly是三个合伙的例程,那就象征调用者将被打断,直到程序的Main方法把调节权交还运转时。

 
 ExecuteAssembly方法存在多少个重载版本,在那地只拿出八个版本来评释。该办法接纳多少个参数,assemblyFile:包涵要实施顺序集的公文的称谓;assemblySecurity:为顺序集提供的证据;args:程序集的入口点的实参。该办法重临 程序集的入口点重返的值。该措施运用Assembly.LoadFrom来加载程序集。有关程序集的剧情将要下朝气蓬勃篇解说。

 
 (5).DoCallBack():在另一个施用程序域中奉行代码,该应用程序域由钦点的寄托标记。

 public void DoCallBack(CrossAppDomainDelegate callBackDelegate)
    {
      if (callBackDelegate == null)
        throw new ArgumentNullException("callBackDelegate");
      callBackDelegate();
    }

 
 那些内定方法必得是静态的,并且它的签订与CrossAppDomainDelegate签字相配。

二、应用程序域

三.程序集操作实例:

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

namespace AppDomainToolkit
{

    /// <summary>
    /// 用于确定加载器应加载哪些加载上下文程序集。
    /// </summary>
    public enum LoadMethod
    {
        /// <summary>
        /// 将程序集加载到LoadFrom上下文中,这将使程序集及其所有引用被发现
                 ///并加载到目标应用程序域中。 尽管它对DLL地狱的倾向,这可能是去的方式
                 /// default,只要确保将应用程序的基本目录传递给AssemblyResolver实例等
                 ///可以正确解析引用。 这也允许同时加载同名的多个程序集
                 ///维护单独的文件名。 这是推荐的方式。
        /// </summary>
        LoadFrom,

        /// <summary>
        /// 使用原始文件名将组合件加载到内存中。 这将以匿名方式加载程序集,因此它不会有
                 ///一个加载上下文。 使用这个,如果你想要的位加载,但确保通过这个文件所在的目录
                 /// AssemblyResolver实例,以便您可以再次找到它。 这是类似于LoadFrom,除非你没有得到免费
                 ///通过融合查找已经存在的程序集名称。 使用它可以更好地控制汇编文件加载。
        /// </summary>
        LoadFile,

        /// <summary>
        /// 使用原始文件名将目标程序集的位加载到内存中。 这本质上是一个动态组件
                 ///为所有的CLR关心。 你将永远不能找到这个与程序集解析器,所以不要使用这,除非你看
                 ///按名称。 小心这一个。
        /// </summary>
        LoadBits
    }

    /// <summary>
    /// 这个类将会把程序集加载到它加载到的任何应用程序域中。 这只是一个简单的方便
    /// wrapper环绕静态Assembly.Load *方法,主要的好处是能够加载程序集
    ///匿名按位。 当您以这种方式加载程序集时,不会有任何DLL文件的锁定。
    /// </summary>
    public class AssemblyLoader : MarshalByRefObject, IAssemblyLoader
    {
        #region Public Methods

        /// <inheritdoc /> 
        /// <remarks>
        /// 如果此实例的LoadMethod设置为LoadBits,并且PDB文件的路径未指定,那么我们将尝试猜测
                 ///到PDB的路径并加载它。 注意,如果一个程序集被加载到内存中而没有调试符号,那么
                 /// image将被抛出。 警惕这个。 使用LoadBits方法加载程序集不会锁定
                 /// DLL文件,因为整个程序集被加载到内存中并且文件句柄被关闭。 但是,
                 ///以这种方式加载的程序集不会有与之关联的位置,因此您必须键入程序集
                 ///它的强名。 当将同一程序集的多个版本加载到一个程序集时,这可能会导致问题
                 ///应用程序域。
        /// </remarks>
        public Assembly LoadAssembly(LoadMethod loadMethod, string assemblyPath, string pdbPath = null)
        {
            Assembly assembly = null;
            switch (loadMethod)
            {
                case LoadMethod.LoadFrom:
                    assembly = Assembly.LoadFrom(assemblyPath);
                    break;
                case LoadMethod.LoadFile:
                    assembly = Assembly.LoadFile(assemblyPath);
                    break;
                case LoadMethod.LoadBits:

                    // Attempt to load the PDB bits along with the assembly to avoid image exceptions.
                    pdbPath = string.IsNullOrEmpty(pdbPath) ? Path.ChangeExtension(assemblyPath, "pdb") : pdbPath;

                    // Only load the PDB if it exists--we may be dealing with a release assembly.
                    if (File.Exists(pdbPath))
                    {
                        assembly = Assembly.Load(
                            File.ReadAllBytes(assemblyPath),
                            File.ReadAllBytes(pdbPath));
                    }
                    else
                    {
                        assembly = Assembly.Load(File.ReadAllBytes(assemblyPath));
                    }

                    break;
                default:
                    // In case we upadate the enum but forget to update this logic.
                    throw new NotSupportedException("The target load method isn't supported!");
            }

            return assembly;
        }

        /// <inheritdoc />
        /// <remarks>
        /// 这个实现将执行目标程序集的尽力负载,它是必需的引用
                 ///进入当前应用程序域。 .NET框架在我们允许使用的调用上锁定我们
                 ///当加载这些程序集时,所以我们需要依赖于AssemblyResolver实例附加的
                 /// AppDomain为了加载我们想要的方式。
        /// </remarks>
        public IList<Assembly> LoadAssemblyWithReferences(LoadMethod loadMethod, string assemblyPath)
        {
            var list = new List<Assembly>();
            var assembly = this.LoadAssembly(loadMethod, assemblyPath);
            list.Add(assembly);

            foreach (var reference in assembly.GetReferencedAssemblies())
            {
                list.Add(Assembly.Load(reference));
            }

            return list;
        }

        /// <inheritdoc />
        /// <remarks>
        /// Just a simple call to AppDomain.CurrentDomain.GetAssemblies(), nothing more.
        /// </remarks>
        public Assembly[] GetAssemblies()
        {
            return AppDomain.CurrentDomain.GetAssemblies();
        }

        #endregion
    }
}

三、浓郁理解.NET上下文

四.总结:

 
 本文主要传授了运用程序域的连带概念,本类别重要疏解.NET对象的跨应用程序域的传递,由于规划使用程序域的始末,所以本文首要解说了有的基本概念,以至部分主导的指标,对于利用程序域富含的主次集的相关内容将要上面举办操作。在实际的门类中,非常少直接取操作使用程序域,比超级多的是一贯操作程序集,所以在本文的最后交给了三个就暗淡的主次集的操作方法。

四、进度应用程序域与线程的关联

 

 

 

大器晚成、进度的概念与成效

进度(Process)是Windows系统中的一个基本概念,它含有着一个周转程序所急需的能源。进度之间是绝对独立的,多个进度不可能直接访问另八个经过的数量(除非动用布满式计算格局),七个进程运转的停业也不会耳濡目染此外进度的运作,Windows系统正是接收进度把职业划分为三个单身的区域的。进度能够精晓为一个顺序的中坚边界。

 

1.1 Process 的品质与情势

在 System.Diagnostics
命名空间个中存在Process类,特地用于管理进度的初叶、停止,访谈进程中的模块,获取进度中的线程,设定进程的事先品级等。
表1.0 展现了Process类的常用属性:

属性 说明
BasePriority 获取关联进程的基本优先级。
ExitCode 获取关联进程终止时指定的值。
ExitTime 获取关联进程退出的时间。
Handle 返回关联进程的本机句柄。
HandleCount 获取由进程打开的句柄数。
HasExited 获取指示关联进程是否已终止的值。
Id 获取关联进程的唯一标识符。
MachineName 获取关联进程正在其上运行的计算机的名称。
MainModule 获取关联进程的主模块。
Modules 获取已由关联进程加载的模块。
PriorityClass 获取或设置关联进程的总体优先级类别。
ProcessName 获取该进程的名称。
StartInfo 获取或设置要传递给Process的Start方法的属性。
StartTime 获取关联进程启动的时间。
SynchronizingObject 获取或设置用于封送由于进程退出事件而发出的事件处理程序调用的对象。
Threads 获取在关联进程中运行的一组线程

 表1.0

除此之外上述个性,Process类也定义了下列平时接收的方式:

方法 说明
GetProcessById 创建新的 Process 组件,并将其与您指定的现有进程资源关联。
GetProcessByName 创建多个新的 Process 组件,并将其与您指定的现有进程资源关联。
GetCurrentProcess 获取新的 Process 组件并将其与当前活动的进程关联。
GetProcesses 获取本地计算机上正在运行的每一个进程列表。
Start 启动一个进程。
Kill 立即停止关联的进程。
Close 释放与此组件关联的所有资源。
WaitForExit 指示 Process 组件无限期地等待关联进程退出。

 表1.1

Process类的详细音信能够参谋 
上边将比方介绍一下Process的选用方法

 

1.2 建构与销毁进度

使用 Start 与Kill 方法能够省略创立也许消逝进度,上面例子正是运用 Start
方法运转记事本的长河,并开垦File.txt文件。2分钟现在,再利用 Kill
方法销毁进程,并关闭记事本。

1         static void Main(string[] args)
2         {
3             Process process = Process.Start("notepad.exe","File.txt");
4             Thread.Sleep(2000);
5             process.Kill();
6         }

 

1.3 列举Computer运维中的进度

在表1.0 中能够看出,使用 GetProcesses
方法能够得到本地计算机上正在运作的每二个历程列表。
而经过的 Id
属性是每种进程的并世无两标记,通过上边包车型客车不二等秘书诀,能够显示当前计算机运转的具备进度新闻。
因为篇幅关系,下边例子只收获前10个经过。

88bifa手机版 4

 1         static void Main(string[] args)
 2         {
 3             var processList = Process.GetProcesses()
 4                 .OrderBy(x=>x.Id)
 5                 .Take(10);
 6             foreach (var process in processList)
 7                 Console.WriteLine(string.Format("ProcessId is:{0} \t ProcessName is:{1}",
 8                     process.Id, process.ProcessName));
 9             Console.ReadKey();
10         }

88bifa手机版 5

运转结果

88bifa手机版 6

 

假使已知进度的Id,就足以因此 GetProcessById 方法获得相应的长河。

88bifa手机版 7

 1         static void Main(string[] args)
 2         {
 3             try
 4             {
 5                 var process = Process.GetProcessById(1772);
 6                 Console.WriteLine("Process name is:" + process.ProcessName);
 7             }
 8             catch (ArgumentException ex)
 9             {
10                 Console.WriteLine("Process is nothing!");
11             }
12             Console.ReadKey();
13         }

88bifa手机版 8

无差别于地,你也大概通过GetProcessByName方法获得五个对应名称的进程。

在乎:假设不可能找到当前ID的历程,系统就能够抛出ArgumentException极度。所以接收办法
GetProcessById 获取进度时应有包涵在 try{…} catch{..} 之内。

 

1.4 获取进度中的五个模块

在表1.0
中包含了Process类的Modules属性,通过此属性大概获得进度中的四个模块。
这几个模块能够是以 *.dll 结尾的程序集,也得以是 *.exe
结尾的可实施程序。
上面包车型客车例证正是通过 Process 的 GetCurrentProcess
方法取伏贴前运作的长河消息,然后展现当前经过的几个模块消息。

88bifa手机版 9

1         static void Main(string[] args)
2         {
3             var moduleList = Process.GetCurrentProcess().Modules;
4             foreach (System.Diagnostics.ProcessModule module in moduleList)
5                 Console.WriteLine(string.Format("{0}\n  URL:{1}\n  Version:{2}",
6                     module.ModuleName,module.FileName,module.FileVersionInfo.FileVersion));
7             Console.ReadKey();
8         }

88bifa手机版 10

运营结果:

88bifa手机版 11

回来目录

 

二、应用程序域

使用.NET创设的可实施程序
*.exe,并从未一贯承继到进度此中,而是承载到应用程序域(AppDomain)在那之中。应用程序域是.NET引进的三个新定义,它比进度所攻克的能源要少,能够被作为是一个轻量级的长河。
在一个进度中能够包涵三个使用程序域,二个接纳程序域能够装载一个可试行程序(*.exe)或然三个程序集(*.dll)。这样能够使应用程序域之间完结深度隔绝,固然进度中的有个别应用程序域现身错误,也不会潜移默化别的应用程序域的例行运营。

当三个顺序集同一时候被几个利用程序域调用时,会冒出三种状态:
先是种处境:CLEvoque分别为差异的施用程序域加载此程序集。
其次种情景:CL中华V把此程序集加载到具备的采取程序域之外,并促成程序集分享,此情状相比特殊,被称作为Domain
Neutral。

 

2.1 AppDomain的天性与艺术

在System命名空间个中就存在AppDomain类,用管理使用程序域。上面是AppDomain类的常用属性:

属性 说明
ActivationContext 获取当前应用程序域的激活上下文。
ApplicationIdentity 获得应用程序域中的应用程序标识。
BaseDirectory 获取基目录。
CurrentDomain 获取当前 Thread 的当前应用程序域。
Id 获得一个整数,该整数唯一标识进程中的应用程序域。
RelativeSearchPath 获取相对于基目录的路径,在此程序集冲突解决程序应探测专用程序集。
SetupInformation 获取此实例的应用程序域配置信息。

表2.0

AppDomain类中有几个措施,能够用来创建二个新的使用程序域,或然推行应用程序域中的应用程序。

方法 说明
CreateDomain 创建新的应用程序域。
CreateInstance 创建在指定程序集中定义的指定类型的新实例。
CreateInstanceFrom 创建在指定程序集文件中定义的指定类型的新实例。
DoCallBack 在另一个应用程序域中执行代码,该应用程序域由指定的委托标识。
ExecuteAssembly 执行指定文件中包含的程序集。
ExecuteAssemblyByName 执行程序集。
GetAssemblies 获取已加载到此应用程序域的执行上下文中的程序集。
GetCurrentThreadId 获取当前线程标识符。
GetData 为指定名称获取存储在当前应用程序域中的值。
IsDefaultAppDomain 返回一个值,指示应用程序域是否是进程的默认应用程序域。
SetData 为应用程序域属性分配值。
Load 将 Assembly 加载到此应用程序域中。
Unload 卸载指定的应用程序域。

表2.1

AppDomain类中有三个事件,用于管理接受程序域生命周期中的差别部分。

事件 说明
AssemblyLoad 在加载程序集时发生。
AssemblyResolve 在对程序集的解析失败时发生。
DomainUnload 在即将卸载 AppDomain 时发生。
ProcessExit 当默认应用程序域的父进程存在时发生。
ReflectionOnlyAssemblyResolve 当程序集的解析在只反射上下文中失败时发生。
ResourceResolve 当资源解析因资源不是程序集中的有效链接资源或嵌入资源而失败时发生。
TypeResolve 在对类型的解析失败时发生。
UnhandledException 当某个异常未被捕获时出现。

表2.2

上面将比方详细介绍一下AppDomain的运用形式

 

2.2 在AppDomain中加载程序集

由表2.第11中学得以见到,通过CreateDomain方法可以建构一个新的选择程序域。
下边包车型大巴事例将利用CreateDomain建构二个应用程序域,并动用Load方法加载程序集Model.dll。最终选择GetAssemblies方法,列举此接受程序域中的全数程序集。

88bifa手机版 12

1         static void Main(string[] args)
2         {
3             var appDomain = AppDomain.CreateDomain("NewAppDomain");
4             appDomain.Load("Model");
5             foreach (var assembly in appDomain.GetAssemblies())
6                 Console.WriteLine(string.Format("{0}\n----------------------------",
7                     assembly.FullName));
8             Console.ReadKey();
9         }

88bifa手机版 13

运作结果

88bifa手机版 14

介怀:当加载程序集后,就不能把它从AppDomain中卸载,只好把全副AppDomain卸载。

当要求在AppDomain加载可实施程序时,能够使用ExecuteAssembly方法。

AppDomain.ExecuteAssembly(“Example.exe”);

 

2.3 卸载AppDomain

通过Unload能够卸载AppDomain,在AppDomain卸载时将会触发DomainUnload事件。
下边包车型大巴例子中,将会采取CreateDomain创建多少个名称为NewAppDomain的行使程序域。然后创立AssemblyLoad的事件处理方法,在前后相继集加载时显得程序集的音信。最终创建DomainUnload事件管理方法,在AppDomain卸载时呈现卸载音讯。

88bifa手机版 15

 1         static void Main(string[] args)
 2         {
 3             //新建名为NewAppDomain的应用程序域
 4             AppDomain newAppDomain = AppDomain.CreateDomain("NewAppDomain");
 5             //建立AssemblyLoad事件处理方法
 6             newAppDomain.AssemblyLoad +=
 7                 (obj, e) =>
 8                 {
 9                     Console.WriteLine(string.Format("{0} is loading!", e.LoadedAssembly.GetName()));
10                 };
11             //建立DomainUnload事件处理方法
12             newAppDomain.DomainUnload +=
13                 (obj, e) =>
14                 {
15                     Console.WriteLine("NewAppDomain Unload!");
16                 };
17             //加载程序集
18             newAppDomain.Load("Model");
19             //模拟操作
20             for (int n = 0; n < 5; n++)
21                 Console.WriteLine("  Do Work.......!");
22              //卸载AppDomain
23             AppDomain.Unload(newAppDomain);
24             Console.ReadKey();
25         }

88bifa手机版 16

运作结果

88bifa手机版 17

 

2.4 在AppDomain中树立程序聚焦钦赐类的目的

使用CreateInstance方法,能创制造进度序集中钦赐类的对像。但接纳此措施将赶回贰个ObjectHandle对象,若要将此值转变为原项目,可调用Unwrap方法。
下边例子会创制Model.dll程序集中的Model.Person对象。

88bifa手机版 18

 1 namespace Test
 2 {
 3      public class Program
 4     {
 5          static void Main(string[] args)
 6          {
 7              var person=(Person)AppDomain.CurrentDomain
 8                           .CreateInstance("Model","Model.Person").Unwrap();
 9              person.ID = 1;
10              person.Name = "Leslie";
11              person.Age = 29;
12              Console.WriteLine(string.Format("{0}'s age is {1}!",person.Name,person.Age));
13              Console.ReadKey();
14          }
15     }
16 }
17 
18 namespace Model
19 {
20     public class Person
21     {
22           public int ID
23           {
24               get;
25               set;
26           }
27           public string Name
28           {
29                get;
30                set;
31           }
32           public int Age
33           {
34                get;
35                set;
36           }
37      }
38 }

88bifa手机版 19

回到目录

三、深切通晓.NET上下文

3.1 .NET上下文的定义

应用程序域是经过中承载程序集的逻辑分区,在选取程序域在这之中,存在越来越细粒度的用于承载.NET对象的实业,这就.NET上下文Context。
具有的.NET对象都设有于上下文此中,每种AppDomain个中起码存在一个私下认可上下文(context
0)。
诚如无需钦赐特定上下文的对象被称之为上下文灵活对象(context-agile),创建此指标没有必要一定的操作,只要求由CLWrangler自行保管,日常那一个目的都会被确立在私下认可上下文个中。

88bifa手机版 20

图3.0

3.2 透金朝理

在上下文的接口个中存在着二个消息采纳器担负检查测验拦截和拍卖音讯,当指标是马尔斯halByRefObject的子类的时候,CL奥迪Q7将会建构透南梁理,实现指标与消息之间的变换。
利用程序域是CLTiggo中财富的界限,日常景况下,应用程序域中的对象不能够被外边的靶子所寻访。而马尔斯halByRefObject
的法力便是允许在扶助远程管理的应用程序中跨应用程序域边界访谈对象,在使用.NET
Remoting远程对象开采时日常应用到的多少个父类。
此小说针没错是经过与应用程序域的功用,关于马尔斯halByRefObject的采纳已经超先生过了本文的范围,关于.NET
Remoting 远程对象开辟可参看:“回看.NET
Remoting布满式开辟”。

 

3.3 上下文绑定

当系统要求对象使用新闻选择器机制的时候,就能够使用ContextBoundObject类。ContextBoundObject承接了马尔斯halByRefObject类,保险了它的子类都会经过透孙吴理被访问。
在第后生可畏节介绍过:平日类所创立的对象为上下文灵活对象(context-agile),它们都由CL奇骏自动处理,可存在于自由的上下文个中。而
ContextBoundObject
的子类所建构的指标只可以在确立它的附和前后文中平常运行,此情形被称之为上下文绑定。其余对象想要访谈ContextBoundObject
的子类对象时,都不能不通过代透明理来操作。

上边包车型大巴例证,是上下文绑定对象与上下文灵活对象的一个比照。Example
是二个普通类,它的靶子会运作在暗中认可上下文个中。而ContextBound类承接了ContextBoundObject,它的指标是三个上下文绑定对象。ContextBound还大概有二个Synchronization天性,此性格会确定保证ContextBound对象被加载到二个线程安全的上下文此中运营。其余,Context类存在ContextProperties属性,通过此属性能够收获该上下文的本来就有新闻。

88bifa手机版 21

 1     class Program
 2     {
 3         public class Example
 4         {
 5             public void Test()
 6             {
 7                 ContextMessage("Example Test\n");
 8             }
 9             //访问上下文绑定对象测试
10             public void Sync(ContextBound contextBound)
11             {
12                 contextBound.Test("Example call on contextBound\n");
13             }
14         }
15 
16         [Synchronization]
17         public class ContextBound:ContextBoundObject
18         {
19             public void Test(string message)
20             {
21                 ContextMessage(message);
22             }
23         }
24 
25         static void Main(string[] args)
26         {
27             Example example = new Example();
28             example.Test();
29             ContextBound contextBound = new ContextBound();
30             contextBound.Test("ContentBound Test\n");
31             example.Sync(contextBound);
32             Console.ReadKey();
33         }
34 
35         //显示上下文信息
36         public static void ContextMessage(string data)
37         {
38             Context context = Thread.CurrentContext;
39             Console.WriteLine(string.Format("{0}ContextId is {1}", data, context.ContextID));
40             foreach (var prop in context.ContextProperties)
41                 Console.WriteLine(prop.Name);
42             Console.WriteLine();
43         }
44     }

88bifa手机版 22

运转结果

88bifa手机版 23

由运营结果能够开采,example对象平常只会做事于私下认可上下文context 0
个中,而contextBound则会做事于线程安全的光景文 context
1个中。当example需求调用contextBound对象时,就能够经过透西汉理把信息直接传送到context
第11中学。
 

回来目录

四、进度、应用程序域、线程的相互关系

4.1 跨AppDomain运营代码

在运用程序域之间的多少是周旋独立的,当须要在此外AppDomain此中实行业前AppDomain中的程序集代码时,可以使用克罗斯AppDomainDelegate委托。把CrossAppDomainDelegate委托绑定方法之后,通过AppDomain的DoCallBack方法就可以实践委托。

88bifa手机版 24

 1         static void Main(string[] args)
 2         {
 3             Console.WriteLine("CurrentAppDomain start!");
 4             //建立新的应用程序域对象
 5             AppDomain newAppDomain = AppDomain.CreateDomain("newAppDomain");
 6             //绑定CrossAppDomainDelegate的委托方法
 7             CrossAppDomainDelegate crossAppDomainDelegate=new CrossAppDomainDelegate(MyCallBack);
 8             //绑定DomainUnload的事件处理方法
 9             newAppDomain.DomainUnload += (obj, e) =>
10             {
11                 Console.WriteLine("NewAppDomain unload!");
12             };
13             //调用委托
14             newAppDomain.DoCallBack(crossAppDomainDelegate);
15             AppDomain.Unload(newAppDomain) ;
16             Console.ReadKey();
17         }
18 
19         static public void MyCallBack()
20         {
21             string name = AppDomain.CurrentDomain.FriendlyName;
22             for(int n=0;n<4;n++)
23             Console.WriteLine(string.Format( "  Do work in {0}........" , name));
24         }

88bifa手机版 25

运行结果

88bifa手机版 26

 

4.2 跨AppDomain的线程

线程存在于经过个中,它在区别的随即能够运作于四个例外的AppDomain当中。它是经过中的基本进行单元,在进程入口施行的第一个线程被视为这一个进程的主线程。在.NET应用程序中,都是以Main()方法作为入口的,当调用此措施时
系统就能够自动成立多个主线程。线程主若是由CPU贮存器、调用栈和线程本地存款和储蓄器(Thread
Local
Storage,TLS)组成的。CPU寄放器主要记录当前所施行线程的事态,调用栈重要用于掩护线程所调用到的内部存款和储蓄器与数码,TLS重要用来寄存线程的情状消息。
有关线程的牵线,可参谋 “C#综述揭秘——细说三十二线程(上)”、“C#回顾揭秘——细说五十多线程(下)” 

上边包车型大巴例子将介绍一下什么跨AppDomain使用线程,首先成立一个ConsoleApplication项目,在进行时输入当前线程及接纳程序域的新闻,最终生成Example.exe的可实施程序。

88bifa手机版 27

1         static void Main(string[] args)
2         {
3             var message = string.Format("  CurrentThreadID is:{0}\tAppDomainID is:{1}",
4                 Thread.CurrentThread.ManagedThreadId, AppDomain.CurrentDomain.Id);
5             Console.WriteLine(message);
6             Console.Read();
7         }

88bifa手机版 28

然后再新建七个ConsoleApplication项目,在那项目中新二个AppDomain对象,在新的AppDomain中通过ExecuteAssembly方法施行Example.exe程序。

88bifa手机版 29

 1         static void Main(string[] args)
 2         {
 3             //当前应用程序域信息
 4             Console.WriteLine("CurrentAppDomain start!");
 5             ShowMessage();
 6             
 7             //建立新的应用程序域对象
 8             AppDomain newAppDomain = AppDomain.CreateDomain("newAppDomain");
 9             //在新的应用程序域中执行Example.exe
10             newAppDomain.ExecuteAssembly("Example.exe");
11 
12             AppDomain.Unload(newAppDomain);
13             Console.ReadKey();
14         }
15 
16         public static void ShowMessage()
17         {
18             var message = string.Format("  CurrentThreadID is:{0}\tAppDomainID is:{1}",
19                 Thread.CurrentThread.ManagedThreadId, AppDomain.CurrentDomain.Id);
20             Console.WriteLine(message);
21         }

88bifa手机版 30

运维结果

88bifa手机版 31

可以知道,ID等于9的线程在不一样一时候间内独家运维于AppDomain 1与AppDomain 2当中。

 

4.3 跨上下文的线程

线程既然能够超越AppDomain的边际,当然也能当先区别的上下文。
上边这么些事例中,线程将同期运营在暗许上下文与提供安全线程的上下文中。

88bifa手机版 32

 1     class Program
 2     {
 3         [Synchronization]
 4         public class ContextBound : ContextBoundObject
 5         {
 6             public void Test()
 7             {
 8                 ShowMessage();
 9             }
10         }
11 
12         static void Main(string[] args)
13         {
14             //当前应用程序域信息
15             Console.WriteLine("CurrentAppDomain start!");
16             ShowMessage();
17 
18             //在上下文绑定对象中运行线程
19             ContextBound contextBound = new ContextBound();
20             contextBound.Test();
21             Console.ReadKey();
22         }
23 
24         public static void ShowMessage()
25         {
26             var message = string.Format("  CurrentThreadID is:{0}\tContextID is:{1}",
27                  Thread.CurrentThread.ManagedThreadId, Thread.CurrentContext.ContextID);
28             Console.WriteLine(message);
29         }
30     }

88bifa手机版 33

运作结果

88bifa手机版 34

 

本篇总括

进度(Process)、线程(Thread)、应用程序域(AppDomain)、上下文(Context)的关系如图5.0,四个历程内得以归纳多少个利用程序域,也可能有富含多个线程,线程也能够不停于三个应用程序域在那之中。但在同一个任何时候,线程只会处在多个选择程序域内。线程也能不断于多少个上下文个中,进行对象的调用。

就算如此经过、应用程序域与上下文在平日的支付中不用平日应用,但深刻地了然三者的关系,熟识其操作方法对合理运用系统的财富,提升系统的功能是充裕有含义的。
一发是三者与线程之间的关联更为关键,特别是在二个十六线程系统中,即使不可能理清其涉及而盲目使用四线程,轻巧形成财富抢占与死锁之类的荒谬。

88bifa手机版 35

 图5.0

 

原稿出处:

相关文章

Leave a Reply

电子邮件地址不会被公开。 必填项已用*标注