COM(C ++)Interlock API是否足以支持AddRef和Release中的Thread Saftey?

时间:2013-08-06 09:46:06

标签: c++ windows winapi com mapi

我知道在COM对象的AddRef和Release方法中使用了互锁API,以增加/减少引用计数线程的安全性。但我试图理解这里是使用Interlock API还是我们需要某种其他同步对象,例如互斥。到目前为止,我见过的所有示例代码都只使用了Interlock API。

场景 - 假设我已实现消息对象的AddRef和Release方法,如下所示。假设线程A访问消息对象,因此m_lRef count为1。完成消息对象使用后,线程A调用Release方法

内部发布方法 -     在第9行 - m_lRef = 1     在第10行 - m_lRef = 0,lRef = 0

线程A在第10行暂停,另一个线程B访问相同的消息,因此它调用AddRef方法,该方法将第3行的m_lRef值设置为1。现在,线程B被挂起,线程A在第11行恢复 - m_lRef = 1,lRef = 0。线程A将删除该对象。现在,如果线程B试图访问同一个对象;崩溃是不可避免的。

我的问题 - 我的方案有效吗?如果m_lRef = 1则理想情况下没有其他线程应该等待访问该对象。但是为了防止在这种意外情况下发生崩溃,我们不应该用互斥锁或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

1 个答案:

答案 0 :(得分:7)

这里的逻辑出错:

  

m_lRef = 0

     

线程A在第10行暂停,另一个线程B访问相同的消息,因此它调用AddRef方法,该方法将第3行的m_lRef值设置为1。现在线程B被挂起,线程A恢复 -

如果线程B持有对该对象的有效COM引用,则单独的线程A不能合法地将计数器减少为零。线程B仍然保留一些东西,所以当线程A释放它拥有的所有东西时,引用计数器应至少为一个......

如果线程B只进行了第一次增量,那么无论如何都应该从某个地方获取接口指针,这假定一个未完成的引用。如果有什么东西在没有强引用的情况下传递指针那么它就是调用者问题,而不是计数问题。

总而言之,Interlocked API非常有效且足以用于引用计数。

相关问题