以下是一种实现发布方法的标准方法(更不用说推荐):IUnknown COM接口(直接取自MSDN):
ULONG CMyMAPIObject::Release()
{
// Decrement the object's internal counter.
ULONG ulRefCount = InterlockedDecrement(m_cRef);
if (0 == m_cRef)
{
delete this;
}
return ulRefCount;
}我在想,如果公寓模型不是STA,是否会出现种族状况?
delete this之前运行并停止。delete this对我来说,确保一致性的唯一方法是创建一个标志,比如说删除,锁定整个关键部分,即除了返回之外的所有释放方法,并将标志设置为true。
在AddRef和QueryInterface方法中,检查此标志,如果设置了标志,则拒绝对新引用的请求。
我遗漏了什么?
提前谢谢。
发布于 2013-10-02 17:47:16
线程2被调度并获得对对象的新引用,例如通过调用QueryInterface或AddRef
只有当它已经具有对IUnknown或对象实现的其他接口之一的引用时,它才能做到这一点。之前对其进行了AddRef()调用。因此,引用计数永远不能通过另一个线程的释放调用减少到小于1的值。
请正确编写代码,必须将ulRefCount与0进行比较,而不是m_cRef。
发布于 2013-10-02 18:01:46
代码中有一个竞争条件,但在您的示例中不是这样的。Release()的此实现具有可能导致未定义行为(通常为“双空闲”)的争用条件。考虑:
m_cRef == 2)Release(),并在运行InterlockedDecrement() (m_cRef == 2)后立即中断。Release()并运行到完成,因此m_cRef == 0因此它调用delete this。if (0 == m_cRef)和m_cRef == 0行继续,因此它再次调用delete this,导致未定义的行为(通常是“双空闲”错误)。正确的实施是:
ULONG CMyMAPIObject::Release()
{
// Decrement the object's internal counter.
ULONG ulRefCount = InterlockedDecrement(m_cRef);
if (0 == ulRefCount) //<<<< THIS FIXES THE PROBLEM
{
delete this;
}
return ulRefCount;
}如果检查需要对本地ulRefCount变量进行检查。因为InterlockedDecrement()返回它递减到的值,所以在线程2的调用中,ulRefCount将只为零,因此delete this只会在线程2上被调用。
if (0 == m_cRef)正在访问没有锁的共享状态,并且不安全。
也见这个问题的答案:Why does this implementation of COM IUnknown::Release work?
https://stackoverflow.com/questions/19142613
复制相似问题