在当前的门类开采中,分布式开荒已经日趋改为主流。三个类型只要未有运用分布式架构,都不佳意思跟外人说那是1个总体的花色。那句话尽管有点偏激,可是随着人们对作用的渴求在增长,以及产品供给进步用户体验。唯有在软件项目标效能和体验做到高水平,才得以获得用户和市镇。

引言

   对于.NET项目,大家应用较多的布满式结构有Webservice,.Net
remoting,MSMQ,WCF,WebAPI等等,大家在利用那些框架的时候,从这一个遍布式框架中获得了很好的用户体验。在.NET项目中,分布式架构对项目标费用也有极大的效用升高。

正文主要是介绍进度(Process)、应用程序域(AppDomain)、.NET上下文(Context)的概念与操作。
固然如此在相似的开垦当中那叁者并不常用,但熟谙3者的涉及,深刻摸底其功用,对增进系统的性质有莫斯中国科学技术大学学的赞助。
在本篇最终的1节当司令员会介绍到3者与线程之间的涉嫌,希望对多线程开拓人士能提供一定的支援。
因为时间匆忙,文中有错误的地点敬请点评。

 
 繁多少人会问,那一个分布式框架的尾巴部分原理是什么吗?恐怕什么人也不敢轻言几句就足以描述完结,在这一个博文种类中,正是一言以蔽之述一下这几个遍及式结构的平底达成原理。

 

 
 本文首要教师对象在使用程序域中的传递。重要教学使用程序域的有个别骨干目的,对于使用程序域的操作出现的相比较少,所以在这边给出的是先后集的局地基本操作。如有不足之处,还望多多指正。

 

一.AppDomain解析:

   
 AppDomain在数不胜数场子都是被翻译为“应用程序域”,在本文中也将应用那一翻译。对于.NET的开垦者,对于CLKoleos应该是最纯熟不过了,CLCR-V类似于java的JVM。在CLOdyssey中,AppDomain规定了代码的进行范围,提供了错误隔断的档期的顺序,提供了三个平安隔开度,并且存有协调的能源。AppDomain的切实功用,有如下图:

  ca88会员入口 1

目录

   1.AppDomain概述:

     
AppDomain类似与系统的进度,进度是有操作系统进行创办,AppDomain是由CL汉兰达实行创办。2个加以的AppDomain必须驻留在多个操作系统的历程中,而二个加以的历程能够住宿两个AppDomain。有如下图:

   ca88会员入口 2

     
如上海体育场所所示,一个对象正好存放在多少个AppDomain种,值也同等。3个AppDomain中的对象引用必须是引用同1AppDomain中的对象,AppDomain的一坐一起就恍如有所本人个人的地点空间。假如八个AppDomain须要使用一个品种,必须为各样AppDomain分别初阶化和分配三回品种。必须为顺序用到花色的AppDomain分别加载和开始化二遍品种的点子和次序集。进度种的顺序AppDomain要保证项目标分歧拷贝。对于项目的静态子类,每一种AppDomain都有其和煦的私家别本。

     AppDomain的能源有如图:

ca88会员入口 3

     
对于应用AppDomain的财富被加载,一直在内部存款和储蓄器中,卸载AppDomain能源是举世无双卸载模块恐怕程序集的渠道,卸载AppDomain财富也是回收类型静态字段所占内部存款和储蓄器的并世无双方式。

   
 在地点提到过操作系统的线程与AppDomain类似,在CL奥迪Q第55中学定义了System.Threading.Thread,在AppDomain中代表为可调解的实体,在此处提议二个新的定义,那便是“软线程”和“硬线程”,顾名思义,操作系统的线程被叫做“硬线程”,CL奇骏中的System.Threading.Thread被叫做“软线程”。一个CLMurano软线程对象驻留在一个明确的AppDomain中;二个加以的AppDomain或然有四个软线程对象。在现阶段的CLSportage中,对于给定的AppDomain,硬线程至多有3个软线程对象属于她,若是多少个硬线程运维在多少个AppDomain中,每一种AppDomain都会有四个鲜明的软线程对象属于该线程。当给定的硬线程进入AppDomain后,就能博得壹致的软线程对象。

一、进度的定义与成效

   二.AppDomain焦点对象解析:

   
 上边介绍了部分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()方法的源码。该方法接收三个string参数,预约义应用程序域属性的名号,或已定义的行使程序域属性的名号。重回二脾性能的值,或
null(尽管属性不存在)。AppDomainSetup类为1个封闭类,表示能够增多到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是二个联合具名的例程,那就意味着调用者将被堵塞,直到程序的Main方法把调整权交还运转时。

 
 ExecuteAssembly方法存在几个重载版本,在此地只拿出二个版本来评释。该办法接收多个参数,assemblyFile:包涵要试行顺序集的公文的称号;assemblySecurity:为顺序集提供的证据;args:程序集的入口点的实参。该方法重回 程序集的入口点重临的值。该办法运用Assembly.LoadFrom来加载程序集。有关程序集的内容就要下1篇讲授。

 
 (5).DoCallBack():在另三个使用程序域中实践代码,该选用程序域由钦赐的嘱托标记。

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

 
 那么些内定方法必须是静态的,并且它的签署与克罗斯AppDomainDelegate签字相配。

二、应用程序域

3.程序集操作实例:

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对象的跨应用程序域的传递,由于设计使用程序域的剧情,所以本文首要教学了一些基本概念,以及部分主干的对象,对于利用程序域包括的顺序集的相干内容就要上边进行操作。在事实上的项目中,很少直接取操作使用程序域,相比多的是间接操作程序集,所以在本文的末梢交给了多少个就暗淡的次第集的操作方法。

4、进度应用程序域与线程的关系

 

 

 

壹、进程的定义与功用

进度(Process)是Windows系统中的二个基本概念,它蕴涵着一个运作程序所急需的能源。进度之间是对峙独立的,一个进度不能够直接待上访问另2个进度的多少(除非动用遍及式总结方式),一个经过运营的挫败也不会影响别的进程的周转,Windows系统正是采纳进程把工作划分为多个独立的区域的。进度可以精通为一个顺序的中央边界。

 

1.一 Process 的属性与艺术

在 System.Diagnostics
命名空间个中存在Process类,专门用来管理进度的启幕、结束,访问进度中的模块,获取进度中的线程,设定进程的优先等第等。
表一.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 列举Computer运营中的进度

在表一.0 中能够看到,使用 GetProcesses
方法能够博得本地Computer上正在周转的每3个进度列表。
而经过的 Id
属性是每一个进度的唯一标识,通过上边包车型地铁章程,能够显妥贴前Computer运转的富有进度新闻。
因为篇幅关系,下边例子只获得前10个经过。

ca88会员入口 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         }

ca88会员入口 5

运作结果

ca88会员入口 6

 

设若已知进度的Id,就足以经过 GetProcessById 方法得到相应的经过。

ca88会员入口 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         }

ca88会员入口 8

因循守旧地,你也说不定由此GetProcessByName方法拿到五个对应名称的进度。

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

 

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

在表1.0
中蕴藏了Process类的Modules属性,通过此属性或者获取进度中的三个模块。
这几个模块可以是以 *.dll 结尾的程序集,也可以是 *.exe
结尾的可试行程序。
上边包车型客车例证正是经过 Process 的 GetCurrentProcess
方法获得当前运转的进程音信,然后显示当前历程的多少个模块新闻。

ca88会员入口 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         }

ca88会员入口 10

运行结果:

ca88会员入口 11

再次回到目录

 

二、应用程序域

使用.NET建设构造的可实施程序
*.exe,并未间接承继到进程在那之中,而是承载到应用程序域(AppDomain)在那之中。应用程序域是.NET引进的三个新定义,它比进度所据有的财富要少,能够被看做是二个轻量级的进度。
在三个进度中得以分包四个应用程序域,3个利用程序域能够装载二个可施行程序(*.exe)或然四个程序集(*.dll)。这样能够使应用程序域之间达成深度隔开,就算进度中的某些应用程序域出现谬误,也不会影响其余使用程序域的正常化运营。

当3个顺序集同时被多少个利用程序域调用时,会冒出三种状态:
率先种情况:CL福特Explorer分别为差别的利用程序域加载此程序集。
其次种情景:CLOdyssey把此程序集加载到持有的行使程序域之外,并促成程序集共享,此情景相比较奇特,被称作为Domain
Neutral。

 

2.壹 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 在AppDomain中加载程序集

由表二.第11中学得以阅览,通过CreateDomain方法能够建立二个新的使用程序域。
上边包车型客车例子将动用CreateDomain建立一个选择程序域,并运用Load方法加载程序集Model.dll。最后接纳GetAssemblies方法,列举此采用程序域中的全部程序集。

ca88会员入口 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         }

ca88会员入口 13

运作结果

ca88会员入口 14

小心:当加载程序集后,就无法把它从AppDomain中卸载,只可以把任何AppDomain卸载。

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

AppDomain.ExecuteAssembly(“Example.exe”);

 

2.3 卸载AppDomain

透过Unload能够卸载AppDomain,在AppDomain卸载时将会触发DomainUnload事件。
下边包车型大巴例子中,将会接纳CreateDomain创建2个名字为NewAppDomain的采纳程序域。然后构造建设AssemblyLoad的事件管理方法,在程序集加载时显得程序集的新闻。最终建构DomainUnload事件管理方法,在AppDomain卸载时显示卸载音讯。

ca88会员入口 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         }

ca88会员入口 16

运作结果

ca88会员入口 17

 

二.四 在AppDomain中确立程序集中钦点类的目的

利用CreateInstance方法,能树立程序聚焦内定类的对像。但运用此格局将重临贰个ObjectHandle对象,若要将此值转化为原项目,可调用Unwrap方法。
下边例子会构造建设Model.dll程序聚集的Model.Person对象。

ca88会员入口 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 }

ca88会员入口 19

回去目录

3、浓厚明白.NET上下文

三.壹 .NET上下文的定义

应用程序域是经过中承载程序集的逻辑分区,在利用程序域当中,存在越来越细粒度的用来承载.NET对象的实业,那就.NET上下文Context。
持有的.NET对象都留存于上下文个中,每种AppDomain在那之中至少存在三个默许上下文(context
0)。
相似无需钦定特定上下文的目标被叫作上下文灵活对象(context-agile),构建此目的没有须要一定的操作,只需要由CLCR-V自行政管理理,一般这么些目标都会被确立在暗中同意上下文个中。

ca88会员入口 20

图3.0

3.二 透汉朝理

在上下文的接口其中存在着贰个新闻接收器肩负检查测试拦截和拍卖音讯,当对象是马尔斯halByRefObject的子类的时候,CLTiggo将会创立透大顺理,达成目的与音信之间的调换。
采用程序域是CLMurano中财富的境界,一般景象下,应用程序域中的对象不可能被外面的对象所走访。而马尔斯halByRefObject
的效率便是允许在支持远程管理的应用程序中跨应用程序域边界访问对象,在使用.NET
Remoting远程对象开拓时经常使用到的三个父类。
此小说针对的是经过与使用程序域的效用,关于马尔斯halByRefObject的利用已经超(Jing Chao)越了本文的限定,关于.NET
Remoting 远程对象开垦可参照:“回想.NET
Remoting分布式开荒”。

 

叁.三 上下文绑定

当系统必要对象使用信息接收器机制的时候,就能够使用ContextBoundObject类。ContextBoundObject承接了马尔斯halByRefObject类,保险了它的子类都会经过透西楚理被访问。
在第一节介绍过:一般类所创设的目的为上下文灵活对象(context-agile),它们都由CL奥德赛自动管理,可存在于自由的上下文个中。而
ContextBoundObject
的子类所确立的对象只可以在建立它的对应前后文中正常运转,此景况被喻为上下文绑定。其余对象想要访问ContextBoundObject
的子类对象时,都只可以通过代透明理来操作。

上面包车型地铁例子,是上下文绑定对象与上下文灵活对象的2个对待。Example
是一个普通类,它的对象会运作在私下认可上下文当中。而ContextBound类承继了ContextBoundObject,它的靶子是八个上下文绑定对象。ContextBound还有3个Synchronization性情,此脾气会有限帮助ContextBound对象被加载到一个线程安全的上下文个中运营。其余,Context类存在ContextProperties属性,通过此属性能够获得该上下文的已有新闻。

ca88会员入口 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     }

ca88会员入口 22

运营结果

ca88会员入口 23

由运营结果能够开采,example对象一般只会做事于暗中同意上下文context 0
个中,而contextBound则会专门的学业于线程安全的前后文 context
3个中。当example必要调用contextBound对象时,就能由此透西楚理把音讯直接传送到context
第11中学。
 

回到目录

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

四.1 跨AppDomain运行代码

在选取程序域之间的数据是绝对独立的,当要求在任何AppDomain其中实行业前AppDomain中的程序集代码时,能够利用克罗斯AppDomainDelegate委托。把克罗斯AppDomainDelegate委托绑定方法之后,通过AppDomain的DoCallBack方法就可以施行委托。

ca88会员入口 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         }

ca88会员入口 25

运作结果

ca88会员入口 26

 

4.2 跨AppDomain的线程

线程存在于经过其中,它在不一样的随时能够运营于多个不等的AppDomain其中。它是经过中的基本举办单元,在进程入口施行的首先个线程被视为那么些进度的主线程。在.NET应用程序中,都以以Main()方法作为入口的,当调用此情势时
系统就能够自动创设3个主线程。线程重假如由CPU寄存器、调用栈和线程本地存款和储蓄器(Thread
Local
Storage,TLS)组成的。CPU寄存器首要记录当前所实践线程的境况,调用栈首要用于维护线程所调用到的内部存储器与数码,TLS重要用以存放线程的境况消息。
有关线程的牵线,可参考 “C#回顾揭秘——细说二十四线程(上)”、“C#综述揭秘——细说二十八线程(下)” 

上边的例子将介绍一下怎么样跨AppDomain使用线程,首先创立三个ConsoleApplication项目,在实行时输入当前线程及运用程序域的音讯,最毕生成Example.exe的可施行程序。

ca88会员入口 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         }

ca88会员入口 28

接下来再新建四个ConsoleApplication项目,在此项目中新2个AppDomain对象,在新的AppDomain中通过ExecuteAssembly方法推行Example.exe程序。

ca88会员入口 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         }

ca88会员入口 30

运作结果

ca88会员入口 31

可知,ID等于玖的线程在分化时间内独家运维于AppDomain 壹与AppDomain 一个中。

 

肆.3 跨上下文的线程

线程既然可以超过AppDomain的界线,当然也能超越不相同的上下文。
上面那一个事例中,线程将同时运维在暗许上下文与提供安全线程的内外文中。

ca88会员入口 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     }

ca88会员入口 33

运维结果

ca88会员入口 34

 

本篇总计

进程(Process)、线程(Thread)、应用程序域(AppDomain)、上下文(Context)的涉及如图伍.0,一个进度内能够归纳八个使用程序域,也有囊括多个线程,线程也得以穿梭于四个应用程序域当中。但在同二个每1天,线程只会处于三个行使程序域内。线程也能不断于八个上下文当中,进行对象的调用。

就算进程、应用程序域与上下文在平凡的支出中毫无平时使用,但深刻地打听三者的关联,领会其操作方法对合理选取系统的财富,升高系统的频率是丰硕有含义的。
越来越是三者与线程之间的涉嫌越发重大,尤其是在二个二十四线程系统中,借使不可能理清其关联而盲目采用八线程,轻易导致财富抢占与死锁之类的不当。

ca88会员入口 35

 图5.0

 

初稿出处:

相关文章