将 COM 接口编组到多个线程时,克隆流是不是足够,还是需要复制?

Posted

技术标签:

【中文标题】将 COM 接口编组到多个线程时,克隆流是不是足够,还是需要复制?【英文标题】:When marshaling a COM interface to multiple threads, is cloning the stream sufficient, or is copying it necessary?将 COM 接口编组到多个线程时,克隆流是否足够,还是需要复制? 【发布时间】:2021-10-28 17:52:18 【问题描述】:

根据Raymond's guide,在将 COM 接口编组到多个线程时,您必须“[t]将流的副本传输到要与之共享对象的每个线程。 " (或者您可以使用互斥体,但我们暂时先搁置该选项。)

我想知道使用IStream::Clone 是否足以达到此目的,或者这是否不算作副本。

另外,如果IStream::Clone 很好,我想知道您是否需要从创建原始流的线程中调用它,或者是否有一个后台线程可以调用它。我想知道,如果后台线程调用它,您是否会遇到我们一开始就试图避免的确切情况(跨线程共享 COM 指针)。

感谢您提供任何信息。

【问题讨论】:

不是从 Windows 8.1 开始,您只需要 RoGetAgileReference(在同一进程中)。 @SimonMourier 是的,我在 Windows 8.1 上尝试了Ro­Get­Agile­Reference,但收到了E_NOTIMPL @SimonMourier RoGetAgileReference() 可用于编组指向线程的接口指针。但它不会为该接口制作单独的副本以供多个线程使用。 什么意义将对象传递给多个线程?所以真的要多次通过同一个任务来池?几乎 100% 这是设计错误 @RbMm 那么为什么 Raymond 会提供如何操作的说明呢?为什么MSHLFLAGS_TABLE­STRONG 存在? 【参考方案1】:

是的,如果不使用同步互斥锁,您需要 Clone() 每个线程的原始流,这样每个克隆都有自己独立于其他克隆的读/写查找位置。

Clone 方法使用自己的查找指针创建一个新的流对象,该指针引用与原始流相同的字节。

Raymond 的指南甚至避开了这一点:

将流的副本传输到要与之共享对象的每个线程。 (你需要使用一个副本,这样多个线程就不会都尝试使用同一个流并踩到彼此的流位置。或者,你可以聪明地使用同一个流,但是使用互斥锁或其他同步对象来确保一次只有一个线程使用流。)

【讨论】:

谢谢。您是否需要从创建原始流的线程中调用IStream::Clone,或者后台线程之一可以调用它?我想知道是否有后台线程调用它,那么您最终会遇到我们一开始就试图避免的确切情况——跨线程共享 COM 指针。 @user15284017 原始线程创建克隆并将它们传递给每个线程会更安全。否则,如果线程尝试创建自己的克隆,则确实存在竞争条件。

以上是关于将 COM 接口编组到多个线程时,克隆流是不是足够,还是需要复制?的主要内容,如果未能解决你的问题,请参考以下文章

为 COM 接口启用编组需要啥?

该应用程序调用了一个为不同线程编组的接口 - Xamarin Forms

应用程序调用了为不同线程编组的接口 - Windows Store App

如何手动将 .NET 对象编组为双 COM 接口?

当他们被传递到另一个 AppDomain 时,是不是可以将代表编组为代理?

为啥 Windows 10 UWP 应用程序由于调用了为不同线程编组的接口而崩溃?