Multithreading COM线程模型-永久混乱

Multithreading COM线程模型-永久混乱,multithreading,com,model,Multithreading,Com,Model,我一直在阅读有关COM线程模型的MSDN文章。在年,我遇到了以下几行: 与其他服务器一样,进程内服务器 可以是单线程, 单元线程,或自由线程 我不知道放什么(COM客户端线程和COM服务器对象)以及放在哪里 如果COM客户端线程调用coinitializex(COINIT\u multi threaded),是否会在MTA上创建可能有多个对象的对象并将此线程放入其中 如果CoInitializeEx(NULL),那么它是否会创建一个新的单元(如果不存在),并将此对象和线程放入其中 若客户端不调

我一直在阅读有关COM线程模型的MSDN文章。在年,我遇到了以下几行:

与其他服务器一样,进程内服务器 可以是单线程, 单元线程,或自由线程

我不知道放什么(COM客户端线程和COM服务器对象)以及放在哪里

  • 如果COM客户端线程调用
    coinitializex(COINIT\u multi threaded)
    ,是否会在MTA上创建可能有多个对象的对象并将此线程放入其中

  • 如果
    CoInitializeEx(NULL)
    ,那么它是否会创建一个新的单元(如果不存在),并将此对象和线程放入其中

  • 若客户端不调用
    CoInitialize
    ,那个么它将创建一个“主机”线程,创建对象并将对象和线程放在其中?这就是上面提到的线所称的单线程吗


我能说的是,那条线是为了制造混乱而设计的

  • 不太可能,COM服务器会在注册表中用ThreadingModel值宣布它们支持的线程模型。这通常是“公寓”(或失踪,同样的事情)。COM将创建一个STA线程,给它一个安全的家。只有当它说“两者”或“自由”时,才会在线程上创建对象,并且不需要封送处理

  • 是的,这将创建一个STA单元,对象将位于该线程上,而不管其ThreadingModel如何

  • 不调用CoInitialize将导致任何COM API失败,包括尝试创建COM对象


我对汉斯的回答投了赞成票,但我也认为也许我可以通过谈论公寓来帮助消除一些困惑。它们是什么?它们为什么存在

考虑公寓的一个好方法是“它是COM对象实例居住的地方”。(实际上,有些实例可以在不同的公寓中同时使用,但这是相对不寻常的,如果您这样做,您就会知道—您的COM类需要一些特殊的工作来实现它)。因此,一般来说,COM对象实例是在单元中创建的,它的整个生命周期都在单元中度过

单线程单元(STA)在任何时候都只能有一个线程执行COM实例代码。如果您是COM类的作者,这允许您做出一些假设。特别是,它使您摆脱了保护内部数据免受并发访问的负担。如果您的编程语言缺少执行此操作所需的功能,这一点尤其重要。我想到了这里的经典VB。这就是最初的公寓类型,这就是为什么我们在需要STA的COM类上标记“公寓”的原因

因为STA中的COM实例只能在该STA的线程上执行,所以当您将对该实例的引用(指针)传递给在不同线程上运行的代码时,事情会变得有趣。如果我在线程A中,并且在线程B上的STA中的COM实例中调用了一个方法,那么一定会发生一些神奇的事情。COM运行时步进,阻止线程A,同时安排COM实例在线程B上执行的一些工作。它实际上使用Windows消息队列来实现这一点。这里的关键概念是拦截:COM在调用者和COM实例之间做一些工作

多个不同的COM实例可以生活在同一单元中,在这种情况下,当它们相互调用时不会发生拦截

有时,作者会选择自己管理并发,以最小化COM拦截的开销,在这种情况下,他可以将自己的COM类标记为“自由”。这意味着他不能依赖于每次调用COM实例时使用的同一个线程,事实上,同一个实例可以同时在多个线程上调用

将COM类标记为“两者”实际上对COM类作者提出了更高的要求。与“Free”类似,这意味着他不能期望对COM实例的每次调用都使用相同的线程,但它也坚持认为,从COM实例到调用代码的任何回调都将发生在调用COM实例的同一线程上。如果COM实例要在STA中正常工作,这是一个必要的限制

总而言之,创建单元是为了让COM类作者可以选择自己准备做多少工作(关于并发性),而不是留给平台多少工作。我认为理解公寓的关键是思考当一个公寓中的代码调用另一个公寓中的代码时发生的拦截