可能有两个相同组件的COM STA实例吗?

时间:2021-12-03 16:18:03

I had a problem discovered on another thread here, I need to access a COM component that is STA. I'll run it on a dual-core computer, a process using this component only reaches 50% of CPU. Unfortunately, the owners said they can't change the component to MTA, because the component is a hybrid system compiled at Matlab, which core is C.

我在另一个线程上发现了一个问题,我需要访问一个STA组件。我将在双核计算机上运行它,使用该组件的进程只能达到CPU的50%。不幸的是,业主表示他们无法将组件更改为MTA,因为该组件是在Matlab编译的混合系统,其核心是C.

So I tried to load two instances of the COM class on the same process, different threads accessing it, but I couldn't, only the last COM instance becomes usable. Do you know anything that could solve this problem?

所以我试图在同一进程上加载两个COM类实例,不同的线程访问它,但我不能,只有最后一个COM实例变得可用。你知道什么可以解决这个问题吗?

I am considering running two processes of my service on the same computer, to achieve 100% cpu. This is not a good solution, mainly because this servers will be installed outside our infra.

我正在考虑在同一台计算机上运行我的服务的两个进程,以实现100%的CPU。这不是一个好的解决方案,主要是因为这些服务器将安装在我们的infra之外。

3 个解决方案

#1


2  

On the topic of multiple STA components

关于多个STA组件的主题

It is possible to have two instances of the same STA COM component and access them from C#. The only thing that could prevent you from such scenario is the object itself if implemented as a singleton object.

可以有两个相同STA COM组件的实例,并从C#访问它们。唯一可能阻止你出现这种情况的是对象本身,如果实现为单例对象。

However, if both instances are on the same STA thread, an active call in one of the instances will block any other calls into that thread. Thus, if you want those two instances to work in parallel, you need to have them be on separate STA threads. Just to be on the safe side, I'd create both instances on background threads. That should prevent your UI from locking.

但是,如果两个实例都在同一个STA线程上,则其中一个实例中的活动调用将阻止对该线程的任何其他调用。因此,如果您希望这两个实例并行工作,则需要将它们放在不同的STA线程上。为了安全起见,我将在后台线程上创建两个实例。这应该会阻止您的UI锁定。

On the topic of STA vs. MTA for the external component

关于外部组件的STA与MTA的主题

I am not sure why the component being in C would prevent it from being an MTA object. Being MTA just means the object needs to internally synchronize it's state access and management code between multiple threads.

我不确定为什么C中的组件会阻止它成为MTA对象。成为MTA只意味着对象需要在多个线程之间内部同步它的状态访问和管理代码。

WARNING: Ugly hack! :-) If you want to experiment a bit, you could go to the registry and change the external component threading model from Apartment to Free, just to verify that your code would work properly with an MTA. Their component will probably break, though, as they probably did not write thread-safe code, relying on COM to guard them.

警告:丑陋的黑客! :-)如果你想进行一些实验,你可以去注册表并将外部组件线程模型从Apartment更改为Free,只是为了验证你的代码是否可以正常使用MTA。但是,他们的组件可能会破坏,因为他们可能没有编写线程安全的代码,依靠COM来保护它们。

Make a note on a prominent place to revert that change later, so that you don't end up with a system where their code doesn't work and spent countless hours chasing ghosts. :-)

在一个突出的位置做一个注释,以便稍后恢复该更改,这样你就不会得到一个他们的代码无法工作的系统,并且花了无数个小时追逐鬼魂。 :-)

#2


0  

Franci Pernov,

I've tried work with two threads, and initialize the com instances on the context of each thread, but the error is the same: (Exception from HRESULT: 0x80004005 (E_FAIL))

我尝试使用两个线程,并在每个线程的上下文中初始化com实例,但错误是相同的:(来自HRESULT的异常:0x80004005(E_FAIL))

I am storing and retrieving the instance through CallContext GetData and SetData.

我通过CallContext GetData和SetData存储和检索实例。

#3


-1  

Try registering a second class using the same DLL. Consider that you may actually need a separate copy of the DLL with a different name in order to be completely safe.

尝试使用相同的DLL注册第二个类。考虑到您可能实际上需要一个具有不同名称的DLL的单独副本,以便完全安全。

Just remember that the STA COM class (and perhaps its DLL) is not considered thread safe for multi-threading and there is nothing you can do about that external to the COM class.

请记住,STA COM类(可能还有它的DLL)不被认为是多线程的线程安全,并且你无法对COM类的外部做任何事情。

#1


2  

On the topic of multiple STA components

关于多个STA组件的主题

It is possible to have two instances of the same STA COM component and access them from C#. The only thing that could prevent you from such scenario is the object itself if implemented as a singleton object.

可以有两个相同STA COM组件的实例,并从C#访问它们。唯一可能阻止你出现这种情况的是对象本身,如果实现为单例对象。

However, if both instances are on the same STA thread, an active call in one of the instances will block any other calls into that thread. Thus, if you want those two instances to work in parallel, you need to have them be on separate STA threads. Just to be on the safe side, I'd create both instances on background threads. That should prevent your UI from locking.

但是,如果两个实例都在同一个STA线程上,则其中一个实例中的活动调用将阻止对该线程的任何其他调用。因此,如果您希望这两个实例并行工作,则需要将它们放在不同的STA线程上。为了安全起见,我将在后台线程上创建两个实例。这应该会阻止您的UI锁定。

On the topic of STA vs. MTA for the external component

关于外部组件的STA与MTA的主题

I am not sure why the component being in C would prevent it from being an MTA object. Being MTA just means the object needs to internally synchronize it's state access and management code between multiple threads.

我不确定为什么C中的组件会阻止它成为MTA对象。成为MTA只意味着对象需要在多个线程之间内部同步它的状态访问和管理代码。

WARNING: Ugly hack! :-) If you want to experiment a bit, you could go to the registry and change the external component threading model from Apartment to Free, just to verify that your code would work properly with an MTA. Their component will probably break, though, as they probably did not write thread-safe code, relying on COM to guard them.

警告:丑陋的黑客! :-)如果你想进行一些实验,你可以去注册表并将外部组件线程模型从Apartment更改为Free,只是为了验证你的代码是否可以正常使用MTA。但是,他们的组件可能会破坏,因为他们可能没有编写线程安全的代码,依靠COM来保护它们。

Make a note on a prominent place to revert that change later, so that you don't end up with a system where their code doesn't work and spent countless hours chasing ghosts. :-)

在一个突出的位置做一个注释,以便稍后恢复该更改,这样你就不会得到一个他们的代码无法工作的系统,并且花了无数个小时追逐鬼魂。 :-)

#2


0  

Franci Pernov,

I've tried work with two threads, and initialize the com instances on the context of each thread, but the error is the same: (Exception from HRESULT: 0x80004005 (E_FAIL))

我尝试使用两个线程,并在每个线程的上下文中初始化com实例,但错误是相同的:(来自HRESULT的异常:0x80004005(E_FAIL))

I am storing and retrieving the instance through CallContext GetData and SetData.

我通过CallContext GetData和SetData存储和检索实例。

#3


-1  

Try registering a second class using the same DLL. Consider that you may actually need a separate copy of the DLL with a different name in order to be completely safe.

尝试使用相同的DLL注册第二个类。考虑到您可能实际上需要一个具有不同名称的DLL的单独副本,以便完全安全。

Just remember that the STA COM class (and perhaps its DLL) is not considered thread safe for multi-threading and there is nothing you can do about that external to the COM class.

请记住,STA COM类(可能还有它的DLL)不被认为是多线程的线程安全,并且你无法对COM类的外部做任何事情。