我一直在阅读有关COM线程模型的MSDN文章。在one of those中,我遇到了以下问题:
与其他服务器,进程内服务器一样 可以是单线程的, 单元线程或自由线程。
我对什么(COM客户端线程和COM服务器对象)放在哪里以及在哪里感到困惑。
如果COM客户端线程调用CoInitializeEx(COINIT_MULTITHREADED)
,是否会在可能有多个对象的MTA上创建对象并将此线程放入其中?
如果CoInitializeEx(NULL)
,那么如果一个不存在,它会创建一个新公寓并将此对象和线程放入其中吗?
如果客户端没有调用CoInitialize
那么它会创建一个“主机”线程,创建对象并在其中放置对象和线程?这是上面提到的那行是单线程吗?
答案 0 :(得分:2)
这条线的设计是为了造成混乱,尽我所知。
不太可能,COM服务器使用ThreadingModel值宣布它们在注册表中支持的线程模型。这通常是“公寓”(或缺少,同样的事情)。 COM将创建一个STA线程,为其提供安全的家。只有当它说“Both”或“Free”时才会在你的线程上创建对象,并且不需要编组。
是的,这会创建一个STA公寓,并且该对象将存在于该线程上,无论其ThreadingModel如何。
不调用CoInitialize会导致任何COM API失败,包括尝试创建COM对象。
答案 1 :(得分:1)
我赞成汉斯的回答,但我也想过,也许我可以通过谈论公寓来解决一些困惑。他们是什么,为什么他们存在?
考虑公寓的好方法是“它是COM对象实例所在的地方”。 (实际上某些实例可能会在不同的公寓中同时使用,但它相对不常见,你会知道你是否这样做 - 你的COM类需要一些特殊的工作来实现它)。因此,通常在公寓中创建一个COM对象实例,并将其一生都花在那里。
单线程单元(STA)是任何时候只有一个线程可以执行COM实例代码的地方。如果您是COM类的作者,这可以让您做出一些假设。特别是它使您免于保护内部数据免受并发访问的负担。如果您的编程语言缺少执行此操作所需的功能,则这一点尤为重要。我在这里想经典VB。所以这是原来的公寓,这就是为什么我们标记需要STA的单词“Apartment”的COM类。
因为STA中的COM实例只能在该STA的线程上执行,所以当您将该实例的引用(指针)传递给在不同线程上运行的代码时,事情会变得很有趣。如果我在线程A中并且我在COM实例中调用一个方法,该实例位于线程B上的STA中,则必须发生一些魔术。 COM运行时介入,阻塞线程A,同时调度线程B上的一些工作以供COM实例执行。它实际上使用Windows消息队列来实现此目的。这里的关键概念是拦截:COM在调用者和COM实例之间做了一些工作。
多个不同的COM实例可以存在于同一个公寓中,在这种情况下,当他们互相呼叫时不会发生拦截。
有时作者会选择将自己管理并发,以便最大限度地减少COM拦截的开销,在这种情况下,他可以将他的COM类标记为“Free”。这意味着每次调用COM实例时都不能依赖于使用的同一个线程,实际上同一个实例可以同时在多个线程上调用。
将COM类标记为“Both”实际上对COM类作者提出了更高的要求。就像“Free”一样,这意味着他不能指望每次调用COM实例都使用相同的线程,但它也坚持从COM实例到调用代码的任何回调都会发生在调用COM实例的同一个线程。如果COM实例要在STA中正常工作,则这是必要的限制。
总而言之,创建了公寓,以便COM类作者可以选择他们自己准备做多少工作(关于并发),以及离开平台多少。我认为理解公寓的关键是考虑当一个公寓的代码在另一个公寓中调用代码时发生的拦截。