我有一个放入 COM+ 应用程序的 STA COM 组件。客户端在该组件中创建该类的多个实例并并行调用它们的方法。该类已正确注册 - 对应类 id 的“ThreadingModel”是“Apartment”。
我看到在组件内部并行执行同一类的同一方法的多个调用 - 在实际组件代码中。它们在同一个进程中执行,但在不同的线程中执行。
发生了什么?COM+ 是否忽略了线程模型?STA模型不应该一次只允许执行一个调用吗?
STA 保证您的对象只能从单个特定线程访问——不需要针对共享变量的保护。
我记得对于 VB6,有一个特殊模式(我不记得它是如何命名的):您可以允许 COM+ 生成多个 STA,每个 STA 使用一个专用对象。然而,这些对象的变量被视为线程本地存储——因此,尽管从多个线程访问您的 COM 类的多个实例,但不会发生变量共享。您是否可能正在使用此功能?
为避免混淆,我不会在此答案中使用“对象”一词。相反,让我们使用“类”和“实例”。我相信我们都理解它们之间的区别。
用“Apartment”的 ThreadingModel 标记您的 COM 类意味着它的实例将被加载到 STA 中。创建这些实例的过程将确定它们是全部进入同一个 STA,还是进入单独的 STA。
正如您所发现的,COM+ 已将多个实例加载到单独的 STA 中。
使用 STA 获得的保证是多个线程永远不会同时访问单个实例。同一个类的不同实例,如果它们被加载到不同的 STA 中,当然可以由不同的线程同时访问。
所以 STA 确实是一种保护您的实例数据的方法。不是你的班级数据。COM 代码中的任何“共享”或“静态”数据都必须受到您的保护。
不,不是。STA 的字面意思是“单线程单元”,这进一步意味着只有一个线程可以在单元中运行。现在的问题是什么是公寓。单元是进程中的一个逻辑空间,其实现可能因框架而异。Microsoft 将单元实现为线程,因为 STA(在 Microsoft 的 COM 上下文中)转换为单线程线程,即可以有多个单元/线程,但在 STA 的情况下每个单元/线程都是单线程的。
您可以自己将这件事概括为 MTA。根据我上面所说,MTA 是 COM 上下文中的多线程线程。
您是否将对象传递给住在另一间公寓的对象?如果是这样,您是否需要在执行之前编组接口?您是否碰巧聚合了免费的线程编组器?
粗略地说,如果您将对象的接口传递给另一个单元(线程)中的对象,那么您必须确保对接口进行编组。如果您不这样做,那么您可能会发现您的对象可以从另一个公寓中的对象自由调用,因为它们没有通过正确处理调用的代理进行调用。
对对象的所有调用都必须在其线程上(在其单元内)进行。禁止直接从另一个线程调用对象;以这种自由线程方式使用对象可能会给应用程序带来问题。这条规则的含义是,所有指向对象的指针在公寓之间传递时都必须进行编组。为此,COM 提供了以下两个函数:
* CoMarshalInterThreadInterfaceInStream marshals an interface into a stream object that is returned to the caller. * CoGetInterfaceAndReleaseStream unmarshals an interface pointer from a stream object and releases it.
这些函数包装对 CoMarshalInterface 和 CoUnmarshalInterface 函数的调用,这需要使用 MSHCTX_INPROC 标志。