COM reference counting - thread safety
If I have a COM开发者_开发技巧 object, is it required for the AddRef() and Release() methods to be thread-safe- i.e., that I have to use atomic operations for my ref count?
Yes, if you are using the free threaded aparement model, use InterlockedIncrement() and InterlockedDecrement() to handle the ref count.
I think the answer is no. It is not required. If you want your COM object to be thread safe then those should be thread safe. Otherwise they do not have to be.
E.g. if you look here: The Rules of the Component Object Model it is not mentioned as a requirement. Also The COM Programmer's Cookbook (Building a COM Component) you can see a sample object without thread safe reference counting.
Microsoft code snippet:
ULONG COutside::AddRef (void)
{
return ++ m_cRef;
}
In practice most implementations would do this because otherwise the COM objects would not be thread safe. If you know the object will only be used in one thread I believe it is an allowed optimization. Not all COM objects are thread safe, I've worked with a few that weren't.
To deal with the fact that COM objects may or may not be thread safe COM offers different "apartments" in which COM objects are created. In a single threaded apartment only a single thread can access objects within that apartment whereas in multi threaded apartment objects can be shared between multiple threads. Quoting from Understanding and Using COM Threading Models:
"Although multi-threaded apartments, sometimes called free-threaded apartments, are a much simpler model, they are more difficult to develop for because the developer must implement the thread synchronization for the objects, a decidedly nontrivial task."
Yup. That is required. COM is a simple binary standard and if you use Free Threaded Apartments, you'll get truly free threaded accesses
This will depend on the threading model you use and the kind of object. Please see the description of _ATL_*_THREADED
macros. Those macros affect thread-safety of AddRef()/Release()
of "usual" classes and of factories.
If you use a "too loose" macro you violate thread-safety requirements and your program might malfunction. If you choose a "too tight" macro you might lose some performance, but you as usual don't know if you care before you profile.
Here's how you choose the right macro (and this explains whether AddRef()/Release()
have to be thread-safe).
If all the classes of a single server have no threading model specified (Main STA) then there's no chance of concurrent access to either objects or factories and they all can have non-threadsafe AddRef()/Release()
and you get this by specifying _ATL_SINGLE_THREADED
macro.
Otherwise if at least one class has "Apartment" model specified you need thread-safe AddRef()/Release()
for the factory of that object but still can have a non-threadsafe AddRef()/Release()
in the object itself and you get this by specifying _ATL_APARTMENT_THREADED
macro. This macro will make all factories have thread-safe AddRef()/Release()
and all object - non-threadsafe AddRef()/Release()
.
Finally if at least one class has "Both" or "Free" threading model specified you need AddRef()/Release()
to be thread-safe in both that class and in the factory and you have to either specify _ATL_FREE_THREADED
or just not specify any of the above - this "most tight" macro effect will be on by default. So the default configuration for COM objects created using ATL is to have thread-safe AddRef()/Release()
for all objects - both served objects and factories.
That said you don't always need AddRef()/Release()
to be thread-safe, but you usually should unless you know for sure that you can get without it and that getting without it lets you gain performance.
精彩评论