You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IUnknown的AddRef与Release是否线程安全?Direct3D12场景求证

IUnknown接口AddRef/Release的线程安全性(含Direct3D 12组件说明)

标准COM的核心要求

标准COM规范明确要求:AddRef和Release方法必须具备线程安全性(原子性),因为COM对象可能被多个线程同时引用。

你提供的两种实现中:

  • 简单增减运算符实现(如下)是非线程安全的:

    ULONG CMyObj::Release()
    {
        if (--m_dwRef == 0)
        {
            delete this;
            return 0;
        }
        return m_dwRef;
    }
    

    多线程环境下,--m_dwRef这类操作可能被打断,导致引用计数计算错误,进而引发对象提前释放或内存泄漏,完全不符合COM规范。

  • Interlocked API实现(如下)才是符合标准要求的正确实现:

    ULONG CMyMAPIObject::Release()
    {
        // Decrement the object's internal counter.
        ULONG ulRefCount = InterlockedDecrement(m_cRef);
        if (0 == m_cRef)
        {
            delete this;
        }
        return ulRefCount;
    }
    

    Interlocked系列API通过系统级原子操作保证计数增减的完整性,避免多线程冲突。

Direct3D 12组件的特殊情况

你提到的“DirectX APIs并非‘标准COM’”的说法准确,但需针对组件类型具体分析:

  • DXGI组件:官方明确说明,2009年3月及以后的DirectX SDK中,DXGI接口的AddRef、Release和QueryInterface可安全并发调用,完全符合线程安全要求。
  • Direct3D 12核心组件(如ID3D12Device、ID3D12DeviceChild及其派生类):
    虽然它们继承自IUnknown,但微软官方文档未直接明确标注这些方法的线程安全性。不过从实际开发经验和设计逻辑来看:
    1. D3D12的核心设计目标就是支持多线程并行渲染,线程安全的引用计数是基础需求,因此其AddRef/Release几乎必然采用原子操作实现。
    2. 社区逆向分析和实际项目验证也显示,这类组件的引用计数操作确实使用了Interlocked系列API。
    3. 注意:仅AddRef/Release线程安全,D3D12组件的其他绝大多数API(如命令队列操作、资源修改等)并非线程安全,必须严格遵循官方文档的线程安全约束。

针对多线程项目的建议

基于你的多线程架构需求:

  1. 对于DXGI组件:放心在多线程环境下调用AddRef/Release。
  2. 对于D3D12核心组件:默认按线程安全的原子操作处理,无需额外加锁保护引用计数。
  3. 所有非引用计数相关的D3D12 API调用,必须严格对照官方文档确认线程安全性,避免跨线程调用非线程安全的方法。

内容的提问来源于stack exchange,提问作者YoonSeok OH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 04:25:37