如果我有一个COM对象,AddRef()和Release()方法是否需要线程安全 - 即,我必须使用原子操作进行引用计数?
答案 0 :(得分:3)
是的,如果您使用的是免费线程公寓模型,请使用InterlockedIncrement()和InterlockedDecrement()来处理引用计数。
答案 1 :(得分:3)
我认为答案是肯定的。它不是必需。如果您希望COM对象是线程安全的,那么这些应该是线程安全的。否则他们不一定是。
E.g。如果你看这里:The Rules of the Component Object Model它没有作为要求提及。 另外The COM Programmer's Cookbook(构建COM组件)您可以看到没有线程安全引用计数的示例对象。
Microsoft代码段:
ULONG COutside::AddRef (void)
{
return ++ m_cRef;
}
在实践中,大多数实现都会这样做,因为否则COM对象将不是线程安全的。如果你知道该对象只会在一个线程中使用,我相信这是一个允许的优化。并非所有COM对象都是线程安全的,我已经使用了一些不是。
要处理COM对象可能是也可能不是线程安全的事实COM提供了创建COM对象的不同“公寓”。在单线程单元中,只有一个线程可以访问该单元内的对象,而多线程单元中的对象可以在多个线程之间共享。引自Understanding and Using COM Threading Models:
“虽然是多线程的公寓, 有时称为自由线程 公寓,是一个更简单的模型, 他们更难以发展 因为开发者必须实施 线程同步 对象,这是一项非常重要的任务。“
答案 2 :(得分:1)
烨。这是必需的。 COM是一个简单的二进制标准,如果您使用Free Threaded Apartments,您将获得真正免费的线程访问
答案 3 :(得分:1)
这取决于您使用的线程模型和对象的类型。请参阅_ATL_*_THREADED
macros的说明。这些宏会影响AddRef()/Release()
“通常”类和工厂的线程安全性。
如果使用“太松”的宏,则违反了线程安全要求,程序可能会出现故障。如果你选择一个“太紧”的宏,你可能会失去一些表现,但你常常在你描述之前不知道你是否在乎。
以下是您选择正确宏的方法(这解释了AddRef()/Release()
是否必须是线程安全的。)
如果单个服务器的所有类都没有指定线程模型(主要STA),则无法同时访问任何对象或工厂,并且它们都可以具有非线程安全AddRef()/Release()
并且您可以通过指定_ATL_SINGLE_THREADED
宏。
否则,如果至少有一个类指定了“Apartment”模型,则该对象的工厂需要线程安全的AddRef()/Release()
,但仍然可以在对象本身中具有非线程安全AddRef()/Release()
通过指定_ATL_APARTMENT_THREADED
宏来获取此信息。这个宏将使所有工厂都具有线程安全AddRef()/Release()
和所有对象 - 非线程安全AddRef()/Release()
。
最后,如果至少有一个类指定了“Both”或“Free”线程模型,则需要AddRef()/Release()
在该类和工厂中都是线程安全的,并且您必须指定{{1}或者只是不指定上述任何一个 - 默认情况下,这个“最紧凑”的宏效果将会打开。因此,使用ATL创建的COM对象的默认配置是为所有对象(服务对象和工厂)提供线程安全的_ATL_FREE_THREADED
。
那就是说你并不总是需要AddRef()/Release()
是线程安全的,但你通常应该除非你确定你可以在没有它的情况下获得它并且没有它就可以获得性能。