最近学习COM(+),由于是新手、自学且没有什么开发经验,遇到了不少问题。下面列出了5个理论上的疑惑,我思前想后,理解不力啊。也许我提的问题本身也有问题,不过还是烦请各位高手帮忙看看,参与讨论并给出你的见解。支持有分,本周日结帖,谢谢!!!每一个COM+对象在外围具有三道边界:进程、套间和环境。当进行跨边界(包括跨进程、同一进程中跨套间和同一套间中跨环境)调用时,调用者和被调用者的对象之间必须加入代理机制,只有处于同一环境中的对象才能进行直接调用。COM+定义了三种对象可以驻留的套间:
①单线程套间(Single-threaded Apartment,STA)
②多线程套间(Multi-threaded Apartment,MTA)
③标准线程套间(Thread-neutral Apartment,TNA)1、在COM+中,只有基于DLL的服务器才能使用COM+的服务。组件可被配置为属于①库应用程序(与客户运行在同一个地址空间)或②服务应用程序(运行在一个独立的地址空间中)。如果所请求的组件属于一个服务应用程序,则当客户激发对象时,SCM(Service Control Manager,服务控制管理器)创建一个代理进程(称作DllHost.exe)并装载组件进这个代理进程。
【疑惑1】如果一个基于DLL的COM组件被配置为COM+服务应用程序,那么这个组件就属于进程外组件了吗?如果是,那组件属于进程内还是属于进程外不再以DLL或EXE为判别标准了吗?此为一基本疑惑,理清它对理解下面几个问题有助。2、由于不同的进程使用不同的地址空间,所以客户不能直接调用进程外组件(包括本地进程外组件和远程组件)。对于跨进程调用,中间必须经过代理/存根(Proxy/Stub)机制和使用列集/散集(Marshaling/Unmarshaling)手段。对于进程外组件对象,客户必须跨进程边界,因此调用始终是间接进行的,中间必须经过调度,而这种调度自动实现了对调用的串行化访问,对象成员函数可以不处理同步。
【疑惑2】照这么说,一个进程外组件,不管其线程模型是什么(哪怕是MTA),都不用手动编码处理同步了吗?好像很矛盾啊。3、套间是线程模型的基本单元,而环境则是列集机制的基本边界。虽然跨套间的调用必须经过代理和存根代码,但是这并不意味着需要经过线程切换,这是环境与套间的重要区别。在跨套间调用过程中,影响性能的主要因素在于线程切换,而不是参数列集和散集处理。
【疑惑3】线程切换很耗性能吗?为什么?4、运行于STA中的组件对象不需要进行同步处理,但对它只能进行串行化访问;而运行于MTA中的组件对象可以并行访问,但组件自身必须保证是线程安全的。我们很难在追求效能和简化程序设计这两者之间保持平衡。COM+引入的TNA和同步域可以很好地解决这个问题,我们可以声明组件的线程模型为TNA,这样的组件对象既可以通过编码保证自身的线程安全性,也可以通过申明同步域属性由COM+自动提供同步保护;另一方面TNA中的对象可被同一进程中的任何线程直接调用,无需线程切换。
【疑惑4】照这么说,STA组件改TNA组件,只要在接口中将属性Apartment改成Neutral就成了,不需要手工编码处理同步,因为可以在COM+中配置同步支持为需要(Required)(注:这样的设置常被称为租借线程(rental-threading)模型)由COM+自动提供同步保护,是这样的吗?如果是,那TNA组件相比STA组件在性能上有什么提升呢?难道是来自同一进程的STA或MTA对TNA的调用不用线程切换,就此而已吗?那如果是来自进程外的客户对TNA的调用还是有线程切换的啊。5、大多COM组件要求在STA中执行,而ASP.Net页面默认情况下运行在MTA中。为了保证和COM组件(包括COM+)的线程模型兼容,ASP.Net经过配置可以运行在STA中。只要在页面的<@ Page />中加一个属性ascompat并将值设为true,ASP.NET就会让页面运行在STA中。这个选项会导致一定的性能损失,但应该可以解决多数COM组件调用问题。
【疑惑5】ASP.Net页面运行在哪个进程内?与IIS的设置有关吗?如果不设置aspcompat属性为true,那调用TNA组件会不会有问题?

解决方案 »

  1.   

    组件属于进程内还是属于进程外以组件和其调用者是否在同一进程空间内为判别标准,
    对于代理进程(称作DllHost.exe)而言,dll的com+组件是进程内组件,客户端调用的是代理进程(称作DllHost.exe)接口中的东东,然后代理进程(称作DllHost.exe)直接或间接调用dll的com+组件。
    说得不对莫怪!
      

  2.   

    【疑惑1】 之个人看法:服务器和客户不在同一进程,当然是进程外服务器。处在代理进程中的 dll 服务器也应该是进程外服务器。【疑惑2】之个人看法:客户调用一个进程外组件(假设其线程模型为 MTA),这个时候 Stub 会建立在该进程外组件的 MTA 中。多个客户就对应有多个 Stub(这些 Stub 会建立在从 COM 线程池中取出的多个线程中,其实关于“COM 对象建立在某个线程中”的说法是有问题的,但大家应该能明白这种说法所想表达的意思),这多个 Stub 可能会同时访问组件。因此线程模型为 MTA 的组件肯定要处理同步问题。 COM+ 中说的“同步”,是由 COM+ 来保证多个 Stub 不会同时访问组件(这里还有很多细节问题需要注意)。楼主的“调度自动实现了对调用的串行化访问”的这种说法,我不敢苟同!
      

  3.   

    【疑惑1】 之个人看法:服务器和客户不在同一进程,当然是进程外服务器。处在代理进程中的 dll 服务器也应该是进程外服务器。【疑惑2】之个人看法:客户调用一个进程外组件(假设其线程模型为 MTA),这个时候 Stub 会建立在该进程外组件的 MTA 中。多个客户就对应有多个 Stub(这些 Stub 会建立在从 COM 线程池中取出的多个线程中,其实关于“COM 对象建立在某个线程中”的说法是有问题的,但大家应该能明白这种说法所想表达的意思),这多个 Stub 可能会同时访问组件。因此线程模型为 MTA 的组件肯定要处理同步问题。 COM+ 中说的“同步”,是由 COM+ 来保证多个 Stub 不会同时访问组件(这里还有很多细节问题需要注意)。楼主的“调度自动实现了对调用的串行化访问”的这种说法,我不敢苟同!
      

  4.   

    【疑惑3】 之个人看法:“环境”是 COM+ 提出的一个概念。“环境是列集机制的基本边界,但是这并不意味着需要经过线程切换。”这跟 Neutral Apartment 有关。跨套间(这里所说的套间不包括 Neutral Apartment)的调用需要线程切换是因为,被调用者方法的执行是在被调用者所处套间的线程中进行,这也就意味着执行这样一个方法,需要从调用者所处套间的某个线程切换到被调用者所处套间的某个线程,执行完后又要切换回来。而如果被调用者处于 Neutral Apartment 中情况则不然,方法的执行直接在调用者所处的线程上进行。少了线程切换,效率肯定要高一些。 关于 Neutral Apartment 的详细信息,可以看 MSDN。线程切换太频繁,系统性能会降低很多。因为机器花了很多时间来进行诸如保护现场之类的工作。
      

  5.   

    【疑惑4】之个人看法:租借线程(rental-threading)模型由 COM+ 自动提供同步保护,是这样的吗?是!——“难道是来自同一进程的 STA 或 MTA 对 TNA 的调用不用线程切换,就此而已吗?那如果是来自进程外的客户对 TNA 的调用还是有线程切换的啊”  楼主可能对 TNA 的期望太高了!跨进程调用的效率本来就很低,不管什么模型都如此。而且 当客户和服务器对象的线程模型不一致时,在服务器进程内还需要额外的线程切换。但是如果 服务器对象为 TNA 模型,则不管客户是 STA 还是 MTA,在服务器进程中是不需要线程切换的。但不可能指望它能大幅度提高远程调用的效率啊!【疑惑5】之个人看法:对 ASP 我不熟。学习!
      

  6.   

    Re 高人leapmars(流铭): 
    “【疑惑2】之个人看法:
    客户调用一个进程外组件(假设其线程模型为 MTA),这个时候 Stub 会建立在该进程外组件的 MTA 中”
       和客户端初始化COM库的方式有关否?
      

  7.   

    To ActiveBeginner:和客户端初始化COM库的方式无关。它和服务器端组件的线程模型有关。我也是才开始研究 COM 的,大家互相交流交流。高人嘛,吾之愿望,不过还差得远呢!^_^
      

  8.   

    对leapmars(流铭)【疑惑2】之个人看法提出的问题:
        多个客户就对应有多个 Stub(这些 Stub 会建立在从 COM 线程池中取出的多个线程中),而此进程外MTA组件只有一个,被这些Stub同时访问。
        那么STA组件呢,是不是多个客户对应有多个Stub,而每一个Stub各自对应一个STA组件?还是和MTA一样呢?恭请leapmars(流铭)兄大驾!
      

  9.   

    对于 STA 组件,多个客户也应该对应有多个 Stub。但是每个 Stub 是否各自对应一个 STA 组件,我个人认为,不一定。这要看该组件相关的类厂是如何实现的。
      

  10.   

    Re 高人leapmars(流铭): 就delphi中的类厂而言,情况是怎样的?李维的书上只说了STA组件,他讲到线程pooling的时候说,com+会为每一个组件程序准备100个STA线程放在池中,当客户端调用组件时,com+会从中拿出一个线程服务于客户端,并将STA组件对象放在此线程对象中执行,给出的图解表示每个线程中都有一个STA组件对象。不知 leapmars(流铭) 兄对此有何见地。
      

  11.   

    在 Delphi 中“COM+ 组件的类厂”跟“自动化对象的类厂”是一样的。但之所以“com+会为每一个组件程序准备100个STA线程放在池中,当客户端调用组件时,com+会从中拿出一个线程服务于客户端,并将STA组件对象放在此线程对象中执行”,这种功能应该是由 COM+ 组件的代理进程 DllHost.exe 提供的。我们可以类比一下 Delphi 中 TComponentFactory 以及 ATL 中 CComAutoThreadModule 的实现。 它们都提供了类似实现“多线程服务器”的功能,但是线程的创建由类厂负责。 而 COM+ 组件的类厂没有也不应该有创建线程的功能,这些事情都由 COM+ 负责。 这也是 COM+ 的好处之一!
      

  12.   

    继续啊我在 VC/MFC ATL/ActiveX/COM 版里发的这个问题就没有什么应答,5~~~这里还好,谢了
      

  13.   

    认同“Delphi 中 TComponentFactory 以及 ATL 中 CComAutoThreadModule 的实现。 它们都提供了类似实现“多线程服务器”的功能”。在TComponentFactory 的creat函数中指定套件类型参数就指定了该类厂能创建何种套件类型的组件,这样该类厂创建的组件对象就会具有或者不具有同步外界访问的能力,这和ATL 中 CComAutoThreadModule相当。我想问的是,如果两个客户端都创建同一个MTA com+组件,那么com+环境是不是只创建创建一个com+对象让两个Stub调用。
      

  14.   

    这个问题不好回答,因为这涉及了 COM+ 基础设施的具体实现。 我也不敢随便下结论。不过你倒是可以编写个程序试试,知道结果后记得告诉我一声! ^_^
      

  15.   

    对于【疑惑4】,又有这样一种说法:只要在代码中剔除那些具有线程紧密性的资源(如窗口句柄、Windows消息等),就能将组件的线程模型从STA安全的转换为TNA,并由COM+自动提供同步保护。Really?