COM引用计数-线程安全

COM reference counting - thread safety

本文关键字:线程 安全 引用 COM      更新时间:2023-10-16

如果我有一个COM对象,是否需要为AddRef()和Release()方法是线程安全的-即,我必须使用我的ref计数原子操作?

是的,如果你正在使用自由线程公寓模型,使用InterlockedIncrement()和InterlockedDecrement()来处理ref count

我认为答案是否定的。它不是必需的。如果你希望你的COM对象是线程安全的,那么那些应该是线程安全的。否则它们不必是。

。如果你看这里:组件对象模型的规则,它并没有作为一个需求被提到。你也可以在《COM程序员的食谱(构建COM组件)》中看到一个没有线程安全引用计数的示例对象。

Microsoft代码片段:

ULONG COutside::AddRef (void)
{
    return ++ m_cRef;
}
在实践中,大多数实现都会这样做,因为否则COM对象将不是线程安全的。如果你知道对象将只在一个线程中使用,我相信这是一个允许的优化。并不是所有的COM对象都是线程安全的,我曾经处理过一些不是的。

为了处理COM对象可能是也可能不是线程安全的事实,COM提供了创建COM对象的不同"公寓"。在单线程公寓中,只有一个线程可以访问该公寓中的对象,而在多线程公寓中,对象可以在多个线程之间共享。引用自理解和使用COM线程模型:

"虽然多线程公寓,有时称为自由线程公寓是一种简单得多的模式,他们更难以发展因为开发人员必须实现的线程同步对象,这绝对是一项不平凡的任务。"

是的。这是必须的。COM是一个简单的二进制标准,如果你使用自由线程公寓,你将获得真正的自由线程访问

这取决于你使用的线程模型和对象的类型。请参见_ATL_*_THREADED宏的描述。这些宏影响"普通"类和工厂的AddRef()/Release()的线程安全。

如果使用"too loose"宏,就违反了线程安全要求,程序可能会出现故障。如果你选择一个"太紧"的宏,你可能会损失一些性能,但你通常不知道你是否关心在你的配置文件。

这是如何选择正确的宏(这解释了AddRef()/Release()是否必须是线程安全的)。

如果单个服务器的所有类都没有指定的线程模型(主STA),那么就没有机会并发访问对象或工厂,它们都可以具有非线程安全的AddRef()/Release(),您可以通过指定_ATL_SINGLE_THREADED宏来获得这一点。

否则,如果至少有一个类有"公寓"模型指定,你需要线程安全的AddRef()/Release()为该对象的工厂,但仍然可以有一个非线程安全的AddRef()/Release()在对象本身,你得到这个通过指定_ATL_APARTMENT_THREADED宏。这个宏将使所有工厂具有线程安全的AddRef()/Release()和所有对象非线程安全的AddRef()/Release()

最后,如果至少有一个类指定了"Both"或"Free"线程模型,那么您需要AddRef()/Release()在该类和工厂中都是线程安全的,并且您必须指定_ATL_FREE_THREADED或不指定上述任何一个-默认情况下,这个"最紧密"的宏效果将被打开。因此,使用ATL创建的COM对象的默认配置是为所有对象(包括服务对象和工厂)提供线程安全的AddRef()/Release()

也就是说,你并不总是需要AddRef()/Release()是线程安全的,但你通常应该这样做,除非你确定你可以不使用它,并且不使用它可以获得性能