FreeThreadedDOMDocument,Neutral Apartments和Free-Threaded Marshaler

时间:2016-07-21 13:13:41

标签: multithreading com marshalling domdocument apartments

正如MSDN所述:

  

如果您正在编写单线程应用程序(或多线程应用程序,其中一次只有一个线程访问DOM),请使用租用线程模型(Msxml2.DOMDocument.3.0或Msxml2.DOMDocument.6.0)。如果您正在编写一个多线程访问将同时访问DOM的应用程序,请使用免费线程模型(Msxml2.FreeThreadedDOMDocument.3.0或Msxml2.FreeThreadedDOMDocument.6.0)。

FreeThreadedDOMDocument,中性公寓和免费线程编组之间是否有任何联系?我查看了OleView,发现FreeThreadedDOMDocument线程模型是两者。据我所知,中性公寓对象由自由线程封送器支持。这是否意味着FreeThreadedDOMDocument没有使用自由线程编组程序,它被称为有点混乱的自由线程?

标记为Free,Both或Neutral的COM类之间的实现差异是什么?据我所知,他们都必须是线程安全的,为什么区别? Neutral应该支持自由线程封送器是否正确?

1 个答案:

答案 0 :(得分:2)

这里有很多问题。

TL; DR:

中立物品:

  • 比STA和MTA对象少了进程内编组
  • 避免线程切换
  • 自动封送接口指针
  • 中立公寓只要有中立的物体就会活着
  • 必须准备好run under any kind of thread,使用COM实用程序函数等待或选择要使用的Win32等待函数,具体取决于线程类型

免费线程对象:

  • 实际上没有进程中编组
  • 避免线程切换
  • 接口指针自动封送
  • 终身与激活公寓相关联
  • 必须准备好run under any kind of thread,使用COM实用程序函数等待或选择要使用的Win32等待函数,具体取决于线程类型
  

FreeThreadedDOMDocument,中性公寓和免费线程编组之间是否有任何联系?

TL; DR:FreeThreadedDOMDocument的线程模型是"两者都是",所以它被绑定到它被激活(创建)的公寓。它聚合了免费的线程编组程序,因此它是一个免费的线程对象。

FreeThreadedDOMDocument是一个COM类,其对象聚合free threaded marshalerWhat this marshaler does是在进程中编组时提供原始指针(即IMarshal::MarshalInterfacedwDestContext设置为MSHCTX_INPROC

我将使用自由线程对象的定义作为聚合自由线程封送器的对象。

免费线程对象的线程模型应指定为" Neutral"或" Both"在Windows 2000之前,它可以在任何线程中创建和使用,避免上下文切换。

如果其线程模型被指定为"两者都是",则对象的生命周期与创建它的公寓相关联。例如,如果STA线程终止,则在该公寓内创建的所有自由线程对象都将被销毁或不再有效。

  

据我所知,中性公寓对象由自由线程封送器支持。

不,中性对象的代理比其他进程内代理稍微轻一点,因为它只设置COM上下文,但它从不会导致完全封送,并且它避免了线程切换。

  

这是否意味着FreeThreadedDOMDocument没有使用自由线程编组程序,它被称为有点混乱的自由线程?

不,FreeThreadedDOMDocument确实使用了免费的线程编组程序。

从历史上看,there were already free threaded objects之前微软为它们提供了自己的支持(由于受欢迎程度,可能因为大多数免费的线程编组程序都存在缺陷),而且中立公寓只出现在Windows 2000中。

因此,FreeThreadedDOMDocument的实例是自由线程化的,因为它们聚合了自由线程封送器,并且每个实例的生命周期都与创建它的公寓相关联。通常情况下,影响不大,但有一些影响,例如一个STA线程的线程池,更频繁地观察到这种影响,因为STA随着拥有线程终止(正常或回收资源)而被创建。例如,传统的ASP默认使用STA线程。

PS:我在another answer中提到了以下主题,但我认为内容有点不同,因为问题也不同。

这是当前的线程模型值:

  • 无:使用主STA
  • "公寓":使用任何STA,即如果当前公寓是STA或NA通过STA,则使用当前STA,否则使用主机 STA(稍后将详细介绍) )
  • "免费":使用MTA
  • "两者":使用当前的公寓
  • "中立":使用NA

对于任何不存在的公寓,如果需要,COM会创建它。

这里有几个特点:

  • 要使用主要的STA,你不能提及任何线程模型,而不是更明智的东西,例如" Main"
  • 除"中立"以外的所有名称现在没有意义:
    • "公寓"感觉就像当前的公寓,但它不是
    • "免"感觉就像免费的线程对象,但它不是
    • "这两种"让你觉得只有2种公寓类型,但有3种:STA,MTA和NA
      • 实际上,从Windows 8开始,有ASTA,这是为GUI创建的一种STA变体,在传出呼叫期间,它会丢弃来电that are not related,从而避免了很大的重入错误来源< / LI>
      • 您可以使用message filter
      • 使常规STA表现得像这样

主STA是第一个创建的STA。它只适用于具有未指定的线程模型的类。

可以有几个STA,但最多只有一个MTA和一个NA。

虽然有一个活动的MTA,但是如果它没有调用CoInitializeEx(NULL, COINIT_MULTITHREADED),那么任何未针对COM初始化的线程都隐含在MTA中,但它也不会影响MTA&#39}。生命周期,意味着MTA可能会在线程使用时被销毁。由于这几乎没有记录,而且非常不可靠,所以你不应该依赖它。

隐式创建的公寓名为host STA and host MTA。你无法控制它们(除非在公寓里与CoUninitialize作弊;注意:实际上并没有这样做)。事实上,如果你激活&#34;公寓&#34;在STA外部或在STA上运行的NA之外的对象,它将在主机STA中被激活。为了进一步混淆,如果主机STA是要初始化的第一个STA,则这也可能是主要的STA。

支持主机公寓的所有COM线程都是后台线程,因此它们不会让您的应用程序退出。

除了在激活中性物体时创建它之外,您无法控制NA。您不能直接输入它,但您可以使用在中性公寓的上下文中运行回调的方法创建自己的中性对象。这个回调可以是一个免费的线程对象。

  

标记为Free,Both或Neutral的COM类之间的实现差异是什么?

公寓的COM课程被宣布为&#34; Free&#34;将导致属于MTA的对象。这些对象可能会假设它们运行的​​线程不必泵送窗口消息。基本上,他们可能会阻止。

必须准备免费的线程对象和中性对象run under any apartment。对于免费的线程对象,应该明白为什么:它绕过任何上下文封送,因此方法在任何线程中执行。对于中性对象,which kind of apartment was active(通过CoGetApartmentType)的区别。

在任何一种情况下,您都应该使用COM的实用程序功能,例如CoWaitForMultipleHandles而不是WaitForMultipleHandles [ Ex ],这会阻止和在STA,或访问窗口消息队列的MsgWaitForMultipleHandles [ Ex ]中是不可接受的,可能会隐式创建它,并且在MTA中通常是不可接受的。

您可以自己检查公寓类型,并选择使用正确的Win32等待功能,或使用轮询策略等待并在STA中抽出超时消息,以防您等待除句柄之外的其他内容或者如果您需要特定的等待逻辑。

自由线程对象和中性对象之间最显着的区别是其他COM对象的编组。

使用中性对象时,传入和传出的接口指针会自动封送。例如,您可以将传入的接口指针存储在字段中。

使用免费的线程对象时,传入和传出的接口指针根本不是 编组,这意味着要么获得指向同一公寓中对象的原始指针,要么获得其他公寓中对象的代理。这些代理也与当前的公寓联系在一起。

例如,传入的原始指针意味着您正在获取属于当前公寓的对象,因此如果您打算存储对该对象的引用,则必须编组它。

传入代理意味着您正在获取另一个公寓中对象的代理,但此代理与当前公寓相关联。您也无法存储此代理。具体而言,尽管标准代理/存根&#39;公寓验证,STA代理可能具有线程亲和力。你也必须整理它。但不要担心,编组代理不会堆叠编组;当您再次解组时,您将获得该对象的代理,而不是代理的代理。

当一个自由线程对象必须存储一个接口指针时,它必须始终通过手动编组来完成,当它必须从该接口指针调用方法时,它必须通过手动解组来实现。

通常,Global Interface Table(GIT;另一个误导性名称,它实际上是进程内表)用于此目的。

  

据我所知,他们都必须是线程安全的,为什么会有区别?

关于线程安全,没有区别。

但正如我在前一个问题中所解释的那样,存储接口指针时存在巨大差异,而且对象激活和生命周期存在细微差别。

  

Neutral应该支持自由线程封送器吗?

免费的线程封送器有效地忽略了公寓,所以它的方法是&#39;有责任正确行事,同步和/或锁定。因此,两个公寓都不能支持免费的线程封送器,它是必须支持每个公寓的免费线程对象。

可以使用任何线程模型聚合对象中的自由线程封送器,包括&#34;中立&#34;。

如果您发现中性公寓封送程序设置的上下文在某种程度上是一个瓶颈,那么您可以考虑使用免费的线程封送程序,但代价是手动封送存储的接口指针。如果没有,只需使用中性公寓。