首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IUnknown.Release标准实现竞赛条件?

IUnknown.Release标准实现竞赛条件?
EN

Stack Overflow用户
提问于 2013-10-02 17:03:04
回答 2查看 1K关注 0票数 2

以下是一种实现发布方法的标准方法(更不用说推荐):IUnknown COM接口(直接取自MSDN):

代码语言:javascript
复制
ULONG CMyMAPIObject::Release()
{
    // Decrement the object's internal counter.
    ULONG ulRefCount = InterlockedDecrement(m_cRef);
    if (0 == m_cRef)
    {
        delete this;
    }
    return ulRefCount;
}

我在想,如果公寓模型不是STA,是否会出现种族状况?

  • 假设还有一个参考资料
  • 线程1通过调用版本来释放它。
  • 它将在delete this之前运行并停止。
  • 线程2被调度并获得对对象的新引用,例如通过调用QueryInterface或AddRef
  • 线程1继续执行并运行delete this
  • 线程2被留下一个无效的对象。

对我来说,确保一致性的唯一方法是创建一个标志,比如说删除,锁定整个关键部分,即除了返回之外的所有释放方法,并将标志设置为true。

在AddRef和QueryInterface方法中,检查此标志,如果设置了标志,则拒绝对新引用的请求。

我遗漏了什么?

提前谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-10-02 17:47:16

线程2被调度并获得对对象的新引用,例如通过调用QueryInterface或AddRef

只有当它已经具有对IUnknown或对象实现的其他接口之一的引用时,它才能做到这一点。之前对其进行了AddRef()调用。因此,引用计数永远不能通过另一个线程的释放调用减少到小于1的值。

请正确编写代码,必须将ulRefCount与0进行比较,而不是m_cRef。

票数 6
EN

Stack Overflow用户

发布于 2013-10-02 18:01:46

代码中有一个竞争条件,但在您的示例中不是这样的。Release()的此实现具有可能导致未定义行为(通常为“双空闲”)的争用条件。考虑:

  1. 线程1&线程2具有对对象的引用(m_cRef == 2)
  2. 线程1调用Release(),并在运行InterlockedDecrement() (m_cRef == 2)后立即中断。
  3. 线程2调用Release()并运行到完成,因此m_cRef == 0因此它调用delete this
  4. 线程1在if (0 == m_cRef)m_cRef == 0行继续,因此它再次调用delete this,导致未定义的行为(通常是“双空闲”错误)。

正确的实施是:

代码语言:javascript
复制
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?

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19142613

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档