Question

I know interlock APIs are used inside to AddRef and Release methods of a COM object to increment/decrement the reference count thread safe. But I am trying to understand here is that is using Interlock APIs enough or we need to some sort of other synchronization objects as well e.g. Mutex. So far all sample code I've seen used only Interlock APIs.

Scenario- Suppose I've implemented the AddRef and Release methods of a message object as following. Let’s say thread A accessing a message object so m_lRef count is 1 . Once it is done with the message object usage thread A calls Release method

Inside Release method – At line#9 - m_lRef = 1 At line#10 - m_lRef = 0, lRef = 0

Thread A suspends at Line#10 and another Thread B access the same message so it calls AddRef method which will set the value of m_lRef value to 1 at line#3. Now Thread B is suspended and Thread A resumes at line#11 – m_lRef =1, lRef = 0 . Thread A will delete the object. Now if Thread B tries to access the same object; Crash is inevitable.

My question - Is my scenario valid? if m_lRef =1 then ideally no other thread should be waiting to access the object. But to prevent crash in such unexpected scenario shouldn't we guard whole release method with mutex or CS ?

1. STDMETHODIMP_(ULONG) CMapiMsg::AddRef()
2. {
3.   LONG lRef = InterlockedIncrement(&m_lRef);
4.   return lRef;
5. }
6.  
7. STDMETHODIMP_(ULONG) CMapiMsg::Release()
8. {
9.    LONG lRef = InterlockedDecrement(&m_lRef);
10.   if(0 == lRef)
11.   {
12.    delete this;
13.   }
14.   return lRef;
15. }

Reference Counting Rules

Was it helpful?

Solution

The logic goes wrong here:

m_lRef = 0

Thread A suspends at Line#10 and another Thread B access the same message so it calls AddRef method which will set the value of m_lRef value to 1 at line#3. Now Thread B is suspended and Thread A resumes-

If thread B hold a valid COM reference to this object, then thread A alone cannot legally decrement counter to zero. Thread B still holds something so reference counter should be at the very least one when thread A releases everything it has...

If thread B only does its first increment, it should anyway get the interface pointer from somewhere, which assumes an outstanding reference. If something is passing the pointer without a strong reference then it's a caller problem, not the counting problem.

All in all, Interlocked API is efficient and sufficient for reference counting.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top