在脚下的档次支付中,分布式开发已经稳步变成主流。2个品种只要未有动用分布式架构,都不佳意思跟人家说那是3个完好无损的品类。那句话固然有点偏激,不过随着人们对成效的渴求在升高,以及产品需求升高用户体验。唯有在软件项指标功能和感受做到高品质,才能够赢得用户和市场。

 
 在当下的项目支付中,分布式开发已经渐渐成为主流。3个项目只要未有行使分布式架构,都倒霉意思跟人家说那是3个完整的体系。那句话即使有个别偏激,可是随着人们对功效的供给在增高,以及产品须求升级用户体验。只有在软件项目标频率和感受做到高品质,才方可博得用户和商海。

引言

   对于.NET项目,大家应用较多的分布式结构有Webservice,.Net
remoting,MSMQ,WCF,WebAPI等等,大家在选择那几个框架的时候,从这个分布式框架中获得了很好的用户体验。在.NET项目中,分布式架构对品种的费用也有十分大的频率升高。

   对于.NET项目,大家选拔较多的分布式结构有Webservice,.Net
remoting,MSMQ,WCF,WebAPI等等,大家在行使那些框架的时候,从那个分布式框架中获取了很好的用户体验。在.NET项目中,分布式架构对品种的开发也有相当大的频率提高。

正文首即便介绍进程(Process)、应用程序域(AppDomain)、.NET上下文(Context)的概念与操作。
尽管在相似的支出在那之中那叁者并不常用,但熟练3者的关系,浓厚摸底其效能,对增高系统的个性有可观的赞助。
在本篇最终的1节当准将会介绍到叁者与线程之间的涉及,希望对八线程开发人士能提供一定的增加帮衬。
因为日子仓促,文中有错误的地点敬请点评。

 
 很四人会问,那几个分布式框架的底层原理是什么呢?恐怕何人也不敢轻言几句就能够描述完结,在那一个博文类别中,正是简单的描述一下那几个分布式结构的尾巴部分达成原理。

 
 很几人会问,那一个分布式框架的底层原理是何许呢?只怕什么人也不敢轻言几句就能够描述实现,在那么些博文种类中,便是简单的描述一下这几个分布式结构的尾巴部分达成原理。

 

 
 本文首要讲解对象在应用程序域中的传递。首要助教使用程序域的有的中坚目的,对于利用程序域的操作出现的可比少,所以在那里给出的是程序集的片段基本操作。如有不足之处,还望多多指正。

 
 本文首要教学对象在利用程序域中的传递。主要讲解使用程序域的局地中坚目的,对于利用程序域的操作出现的相比较少,所以在此间给出的是先后集的1部分基本操作。如有不足之处,还望多多指正。

 

一.AppDomain解析:

   
 AppDomain在众多场地都是被翻译为“应用程序域”,在本文中也将运用那1翻译。对于.NET的开发者,对于CLQashqai应该是最熟稔但是了,CLOdyssey类似于java的JVM。在CLENCORE中,AppDomain规定了代码的进行范围,提供了不当隔开的水准,提供了1个康宁隔断度,并且有所和谐的财富。AppDomain的现实作用,有如下图:

  图片 1

一.AppDomain解析:

   
 AppDomain在不少场子都是被翻译为“应用程序域”,在本文中也将运用那1翻译。对于.NET的开发者,对于CLTucson应该是最熟稔然而了,CL帕杰罗类似于java的JVM。在CLCR-V中,AppDomain规定了代码的实践范围,提供了错误隔开分离的品位,提供了一个有惊无险隔开分离度,并且拥有自身的能源。AppDomain的现实性职能,有如下图:

  图片 1

目录

   1.AppDomain概述:

     
AppDomain类似与系统的经过,进程是有操作系统进行创办,AppDomain是由CLTucson实行创办。3个加以的AppDomain必须驻留在一个操作系统的长河中,而3个加以的进程能够借宿八个AppDomain。有如下图:

   图片 3

     
如上海教室所示,3个指标正好存放在四个AppDomain种,值也如出1辙。2个AppDomain中的对象引用必须是援引同壹AppDomain中的对象,AppDomain的行事就类似有所本人个人的地方空间。假如多个AppDomain须要动用一个品种,必须为各样AppDomain分别初叶化和分配一回品种。必须为顺序用到项指标AppDomain分别加载和开始化三回品种的艺术和程序集。进度种的顺序AppDomain要维护项目标比不上拷贝。对于项目标静态子类,每一种AppDomain都有其本人的个人副本。

     AppDomain的财富有如图:

图片 4

     
对于应用AppDomain的财富被加载,一贯在内部存款和储蓄器中,卸载AppDomain财富是绝无仅有卸载模块大概程序集的路子,卸载AppDomain财富也是回收类型静态字段所占内部存款和储蓄器的绝无仅有方法。

   
 在地方提到过操作系统的线程与AppDomain类似,在CL景逸SUV中定义了System.Threading.Thread,在AppDomain中意味为可调度的实业,在那边建议2个新的定义,这正是“软线程”和“硬线程”,顾名思义,操作系统的线程被称作“硬线程”,CL福特Explorer中的System.Threading.Thread被号称“软线程”。一个CL福睿斯软线程对象驻留在八个明显的AppDomain中;贰个加以的AppDomain或者有七个软线程对象。在此时此刻的CL科雷傲中,对于给定的AppDomain,硬线程至多有一个软线程对象属于她,若是三个硬线程运营在多个AppDomain中,每种AppDomain都会有三个强烈的软线程对象属于该线程。当给定的硬线程进入AppDomain后,就会得到平等的软线程对象。

   1.AppDomain概述:

     
AppDomain类似与系统的经过,进度是有操作系统进行创办,AppDomain是由CL途观实行创办。3个加以的AppDomain必须驻留在三个操作系统的长河中,而一个加以的进程能够借宿多个AppDomain。有如下图:

   图片 3

     
如上海体育场面所示,3个目的正好存放在3个AppDomain种,值也一致。二个AppDomain中的对象引用必须是援引同1AppDomain中的对象,AppDomain的作为就就像是有所和谐个人的地方空间。借使四个AppDomain须求运用贰个体系,必须为每一种AppDomain分别起首化和分红贰回品种。必须为顺序用到花色的AppDomain分别加载和开始化3回品种的法子和次序集。进度种的逐一AppDomain要保障项指标两样拷贝。对于项指标静态子类,各样AppDomain都有其和好的个体副本。

     AppDomain的财富有如图:

图片 4

     
对于应用AppDomain的能源被加载,一贯在内部存储器中,卸载AppDomain能源是绝无仅有卸载模块只怕程序集的途径,卸载AppDomain能源也是回收类型静态字段所占内部存款和储蓄器的绝无仅有格局。

   
 在上头提到过操作系统的线程与AppDomain类似,在CL福睿斯中定义了System.Threading.Thread,在AppDomain中代表为可调度的实体,在此处提议二个新的定义,那便是“软线程”和“硬线程”,顾名思义,操作系统的线程被喻为“硬线程”,CLCRUISER中的System.Threading.Thread被喻为“软线程”。3个CLXC60软线程对象驻留在二个显著的AppDomain中;二个加以的AppDomain可能有七个软线程对象。在日前的CLRAV肆中,对于给定的AppDomain,硬线程至多有二个软线程对象属于她,若是3个硬线程运营在多少个AppDomain中,每种AppDomain都会有3个肯定的软线程对象属于该线程。当给定的硬线程进入AppDomain后,就会获取相同的软线程对象。

一、进程的定义与效能

   二.AppDomain大旨对象解析:

   
 上边介绍了1些AppDomain的基本概念,接下去大家来简单了然一下AppDomain的相干操作和着力目的。在.NET种可以因此System.AppDomain类型访问AppDomain。在此地大家实际明白一下System.AppDomain类型的诀要和质量。对于此类的辨证:  

   (壹).CurrentDomain:获取当前Thread 的此时此刻采取程序域。

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

   
由上述代码可见,该属性为二个静态属性,并且只有贰个只读属性。该属性只是简短地领到存款和储蓄在硬线程的TLS(线程本地存款和储蓄区)中的AppDomain引用。你可以在Thread.CurrentThread属性中,从硬线程的TLS中提取当前的软线程对象。 

   (二).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()方法的源码。该措施接收3个string参数,预约义应用程序域属性的称号,或已定义的选择程序域属性的称号。重临叁天性质的值,或
null(假使属性不设有)。AppDomainSetup类为3个封闭类,表示能够增加到System.AppDomain的实例的程序集绑定音信。

 
 (三).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:包涵应用程序域起首化新闻的目的。该形式重返一个新创立的选取程序域。

 
 (四).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);
    }

 
 当创设2个AppDomain后,能够动用壹多级技术强制它加载和施行代码,可以选用ExecuteAssembly方法。该方法将对象AppDomain加载到程序集中,并且实施其主入口点。在父AppDomain种,ExecuteAssembly方法不会加载大概初步化钦赐的程序集。ExecuteAssembly是2个1并的例程,那就意味着调用者将被卡住,直到程序的Main方法把控制权交还运维时。

 
 ExecuteAssembly方法存在多少个重载版本,在这里只拿出2个版本来表明。该办法接收多少个参数,assemblyFile:包括要履行顺序集的文本的名号;assemblySecurity:为顺序集提供的证据;args:程序集的入口点的实参。该方法重返 程序集的入口点重临的值。该办法运用Assembly.LoadFrom来加载程序集。有关程序集的内容将在下壹篇讲解。

 
 (5).DoCallBack():在另二个运用程序域中实行代码,该应用程序域由内定的委托标识。

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

 
 这些钦点方法必须是静态的,并且它的签名与克罗斯AppDomainDelegate签名匹配。

   2.AppDomain核心对象解析:

   
 上边介绍了有的AppDomain的基本概念,接下去大家来大约理解一下AppDomain的连带操作和着力指标。在.NET种能够通过System.AppDomain类型访问AppDomain。在那里我们现实明白一下System.AppDomain类型的主意和脾气。对于此类的认证:  

   (一).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;
      }
    }

 
 每3个AppDomain有和好的条件属性集,能够经过SetData和GetData方法访问,在那里给出了GetData()方法的源码。该方式接收四个string参数,预约义应用程序域属性的称呼,或已定义的使用程序域属性的称谓。重返二个天性的值,或
null(倘使属性不存在)。AppDomainSetup类为一个封闭类,表示能够加上到System.AppDomain的实例的程序集绑定音信。

 
 (三).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:包括应用程序域初叶化新闻的对象。该方法重回二个新创造的施用程序域。

 
 (四).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后,能够采用1连串技术强制它加载和执行代码,能够使用ExecuteAssembly方法。该办法将目的AppDomain加载到程序集中,并且实施其主入口点。在父AppDomain种,ExecuteAssembly方法不会加载只怕开头化钦命的顺序集。ExecuteAssembly是1个合伙的例程,那就表示调用者将被堵塞,直到程序的Main方法把控制权交还运营时。

 
 ExecuteAssembly方法存在多少个重载版本,在那边只拿出1个版本来表明。该办法接收五个参数,assemblyFile:包罗要履行顺序集的文本的名号;assemblySecurity:为顺序集提供的证据;args:程序集的入口点的实参。该方法重回 程序集的入口点再次回到的值。该办法运用Assembly.LoadFrom来加载程序集。有关程序集的内容将在下壹篇讲解。

 
 (5).DoCallBack():在另多个利用程序域中实施代码,该行使程序域由内定的委托标识。

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

 
 那么些钦赐方法必须是静态的,并且它的署名与克罗丝AppDomainDelegate签名相称。

2、应用程序域

三.程序集操作实例:

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
    }
}

三.程序集操作实例:

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对象的跨应用程序域的传递,由于设计使用程序域的剧情,所以本文首要教学了壹部分基本概念,以及部分基本的对象,对于利用程序域包涵的先后集的相关内容将在上边实行操作。在事实上的档次中,很少直接取操作使用程序域,相比较多的是直接操作程序集,所以在本文的末梢交给了1个就暗淡的程序集的操作方法。

四.总结:

 
 本文首要讲解了运用程序域的相干概念,本种类首要讲解.NET对象的跨应用程序域的传递,由于设计使用程序域的始末,所以本文首要讲解了一些基本概念,以及部分中坚的指标,对于利用程序域包涵的次第集的相干内容将在下边进行操作。在实质上的品种中,很少直接取操作使用程序域,相比较多的是直接操作程序集,所以在本文的末梢交给了3个就暗淡的主次集的操作方法。

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

 

 

 

壹、进度的概念与效能

进度(Process)是Windows系统中的多少个基本概念,它含有着一个运作程序所供给的财富。进度之间是对峙独立的,3个历程不或者间接待上访问另3个进度的数据(除非选择分布式计算情势),三个进度运营的挫败也不会影响其余进度的周转,Windows系统便是运用进度把工作划分为三个独立的区域的。进度能够清楚为多少个顺序的主干边界。

 

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的施用方法

 

一.2 建立与销毁进程

应用 Start 与Kill 方法能够大约建立也许灭绝进程,上边例子就是接纳 Start
方法运营记事本的长河,并开拓File.txt文件。二分钟以往,再选择 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 列举总计机械运输转中的进程

在表壹.0 中得以观看,使用 GetProcesses
方法能够赢得本地电脑上正在运维的每1个进度列表。
而经过的 Id
属性是种种进程的绝无仅有标志,通过上边包车型地铁主意,能够来妥善前总计机运营的装有进度新闻。
因为篇幅关系,上边例子只得到前12个进程。

图片 7

 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         }

图片 8

运维结果

图片 9

 

1旦已知进度的Id,就能够透过 GetProcessById 方法获得相应的历程。

图片 10

 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         }

图片 11

1致地,你也可能通过GetProcessByName方法得到多少个对应名称的经过。

在意:即便不能够找到当前ID的进度,系统就会抛出ArgumentException十分。所以选择办法
GetProcessById 获取进程时应当包涵在 try{…} catch{..} 之内。

 

一.四 获取进度中的多少个模块

在表壹.0
中含有了Process类的Modules属性,通过此属性也许获取进度中的多少个模块。
这一个模块能够是以 *.dll 结尾的程序集,也得以是 *.exe
结尾的可执行程序。
下边的事例就是经过 Process 的 GetCurrentProcess
方法获得当前运转的进程音信,然后突显当前经过的七个模块信息。

图片 12

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         }

图片 13

运转结果:

图片 14

回到目录

 

2、应用程序域

使用.NET建立的可执行程序
*.exe,并未平昔承接到进度当中,而是承载到应用程序域(AppDomain)当中。应用程序域是.NET引进的二个新定义,它比进度所占有的能源要少,可以被看做是一个轻量级的进度。
在一个进程中得以涵盖几个使用程序域,一个采纳程序域能够装载叁个可执行程序(*.exe)可能八个程序集(*.dll)。那样能够使应用程序域之间达成深度隔开分离,固然进度中的有个别应用程序域出现谬误,也不会影响别的使用程序域的正规运转。

当1个顺序集同时被七个使用程序域调用时,会见世三种状态:
率先种情状:CL路虎极光分别为差异的利用程序域加载此程序集。
其次种情景:CLCR-V把此程序集加载到具有的行使程序域之外,并落到实处程序集共享,此情景相比卓殊,被称作为Domain
Neutral。

 

二.1 AppDomain的品质与方式

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

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

表2.0

AppDomain类中有多少个艺术,能够用来创设3个新的利用程序域,只怕实施应用程序域中的应用程序。

方法 说明
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.二 在AppDomain中加载程序集

由表贰.第11中学得以看到,通过CreateDomain方法能够建立二个新的使用程序域。
上边包车型地铁例子将应用CreateDomain建立一个用到程序域,并运用Load方法加载程序集Model.dll。最终选用GetAssemblies方法,列举此选用程序域中的全数程序集。

图片 15

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         }

图片 16

运转结果

图片 17

小心:当加载程序集后,就没办法把它从AppDomain中卸载,只可以把方方面面AppDomain卸载。

当供给在AppDomain加载可执行程序时,可以使用ExecuteAssembly方法。

AppDomain.ExecuteAssembly(“Example.exe”);

 

2.3 卸载AppDomain

透过Unload能够卸载AppDomain,在AppDomain卸载时将会触发DomainUnload事件。
上边包车型客车事例中,将会使用CreateDomain建立三个名称叫NewAppDomain的使用程序域。然后建立AssemblyLoad的事件处理方法,在先后集加载时展现程序集的新闻。最终建立DomainUnload事件处理方法,在AppDomain卸载时显得卸载音信。

图片 18

 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         }

图片 19

运行结果

图片 20

 

二.四 在AppDomain中确立程序集中钦命类的对象

选拔CreateInstance方法,能成立程序集中钦赐类的对像。但利用此办法将回来3个ObjectHandle对象,若要将此值转化为原项目,可调用Unwrap方法。
上边例子会创建Model.dll程序集中的Model.Person对象。

图片 21

 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 }

图片 22

回到目录

三、深远理解.NET上下文

三.一 .NET上下文的概念

选择程序域是经过中承载程序集的逻辑分区,在运用程序域在那之中,存在更加细粒度的用于承载.NET对象的实业,那就.NET上下文Context。
不无的.NET对象都留存于上下文个中,每一种AppDomain当中至少存在一个暗中同意上下文(context
0)。
一般不必要钦点特定上下文的目的被号称上下文灵活对象(context-agile),建立此指标不须求一定的操作,只要求由CL奥迪Q五自行政管理理,1般那个指标都会被确立在私下认可上下文当中。

图片 23

图3.0

三.二 透清代理

在上下文的接口在那之中存在着二个音信接收器负责检验拦截和拍卖音讯,当目的是MarshalByRefObject的子类的时候,CLRAV4将会建立透南齐理,实现指标与音讯之间的转换。
利用程序域是CL安德拉中财富的疆界,1般景色下,应用程序域中的对象无法被外面包车型客车对象所走访。而马尔斯halByRefObject
的意义正是允许在帮忙远程处理的应用程序中跨应用程序域边界访问对象,在使用.NET
Remoting远程对象开发时平时应用到的3个父类。
此小说针对的是进度与运用程序域的功力,关于马尔斯halByRefObject的选择已经超先生过了本文的限制,关于.NET
Remoting 远程对象开发可参照:“回想.NET
Remoting分布式开发”。

 

三.三 上下文绑定

当系统供给对象使用新闻接收器机制的时候,即可使用ContextBoundObject类。ContextBoundObject继承了马尔斯halByRefObject类,保障了它的子类都会因而透南梁理被访问。
在第二节介绍过:壹般类所树立的对象为上下文灵活对象(context-agile),它们都由CLRAV肆自动管理,可存在于自由的上下文其中。而
ContextBoundObject
的子类所建立的靶子只可以在建立它的应和前后文中不荒谬运营,此情形被号称上下文绑定。其余对象想要访问ContextBoundObject
的子类对象时,都不得不通过代透明理来操作。

上边包车型客车例子,是上下文绑定对象与上下文灵活对象的3个对待。Example
是1个普通类,它的对象会运作在默许上下文个中。而ContextBound类继承了ContextBoundObject,它的目的是八个上下文绑定对象。ContextBound还有三个Synchronization特性,此天性会确认保证ContextBound对象被加载到2个线程安全的上下文个中运营。其余,Context类存在ContextProperties属性,通过此属性能够收获该上下文的已有音讯。

图片 24

 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     }

图片 25

运营结果

图片 26

由运转结果能够窥见,example对象一般只会工作于私下认可上下文context 0
当中,而contextBound则会做事于线程安全的内外文 context
1在那之中。当example需求调用contextBound对象时,就会因此透东汉理把消息一向传送到context
第11中学。
 

回到目录

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

四.一 跨AppDomain运维代码

在动用程序域之间的数额是周旋独立的,当需要在任何AppDomain个中进行当前AppDomain中的程序集代码时,能够应用克罗丝AppDomainDelegate委托。把克罗丝AppDomainDelegate委托绑定方法之后,通过AppDomain的DoCallBack方法即可进行委托。

图片 27

 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         }

图片 28

运营结果

图片 29

 

4.2 跨AppDomain的线程

线程存在于经过当中,它在差异的每一天能够运作于八个例外的AppDomain个中。它是进度中的基本实行单元,在经过入口实施的率先个线程被视为那么些历程的主线程。在.NET应用程序中,都是以Main()方法作为入口的,当调用此措施时
系统就会活动创制三个主线程。线程主假诺由CPU寄存器、调用栈和线程本地存款和储蓄器(Thread
Local
Storage,TLS)组成的。CPU寄存器首要记录当前所推行线程的气象,调用栈首要用来掩护线程所调用到的内部存款和储蓄器与数据,TLS主要用于存放线程的情形信息。
关于线程的介绍,可参考 “C#归咎揭秘——细说二十四线程(上)”、“C#综合揭秘——细说拾二线程(下)” 

上面包车型客车事例将介绍一下怎么跨AppDomain使用线程,首先创立3个ConsoleApplication项目,在履行时输入当前线程及选用程序域的新闻,最终生成Example.exe的可执行程序。

图片 30

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         }

图片 31

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

图片 32

 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         }

图片 33

运作结果

图片 34

足见,ID等于九的线程在不相同时间内各自运转于AppDomain 一与AppDomain 二其中。

 

4.三 跨上下文的线程

线程既然能够跨越AppDomain的界线,当然也能超越不一样的上下文。
下边这些事例中,线程将同时运转在暗许上下文与提供安全线程的光景文中。

图片 35

 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     }

图片 36

运维结果

图片 37

 

本篇总计

进度(Process)、线程(Thread)、应用程序域(AppDomain)、上下文(Context)的涉及如图5.0,三个进度内足以包罗多个使用程序域,也有囊括多少个线程,线程也得以穿梭于四个应用程序域个中。但在同多个时刻,线程只会处在2个选拔程序域内。线程也能不断于四个上下文在那之中,实行对象的调用。

尽管进度、应用程序域与上下文在平凡的支出中永不常常使用,但长远地打听3者的涉及,熟知其操作方法对合理使用体系的能源,升高系统的频率是老大有含义的。
越来越是三者与线程之间的涉嫌更为首要,特别是在1个多线程系统中,若是无法理清其涉及而盲目选取四线程,不难造成财富抢占与死锁之类的不当。

图片 38

 图5.0

 

初稿出处:

相关文章