6

我知道在 COM 对象的 AddRef 和 Release 方法内部使用互锁 API 来增加/减少引用计数线程安全。但我想在这里理解的是,使用互锁 API 是否足够,或者我们还需要某种其他同步对象,例如互斥锁。到目前为止,我看到的所有示例代码都只使用了 Interlock API。

场景- 假设我已经实现了消息对象的 AddRef 和 Release 方法,如下所示。假设线程 A 访问消息对象,因此 m_lRef 计数为 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 则理想情况下不应有其他线程等待访问该对象。但是为了防止在这种意外情况下崩溃,我们不应该用 mutex 或 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. }

引用计数规则

4

1 回答 1

7

这里的逻辑出错了:

m_lRef = 0

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

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

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

总而言之,Interlocked API 对于引用计数来说是高效且足够的。

于 2013-08-06T09:57:01.707 回答