直接返回InterlockedDecrementRelease() 的结果和先把结果存入变量再返回之间有区别吗?

后端开发 2026-07-12

我想知道下面这两段代码是否有差异。

我在一个智能引用/指针实现中看到了第一段,作为引用计数的一部分。

int Dec() const
{
    int ret = InterlockedDecrementRelease(&_count);
    return ret;
}

该方法调用Windows API以原子方式减少 _count(它是一个可变的volatile变量)。它实际上只在Windows的 x86架构上进行编译,因此我推测 InterlockedDecrementRelease()InterlockedDecrement() 相同。

但我想知道它是否会与下面的代码段不同

int Dec() const
{
    return InterlockedDecrementRelease(&_count);
}

在普通函数的情况下,我会认为带优化的编译器会生成相同的代码。

但在多线程和涉及屏障的函数中,我不确定中间变量是否有特殊用途,还是仅仅是一种编码风格。

解决方案

完全没有差异。中间变量没有任何意义。多线程和它有什么关系?

"我假设 InterlockedDecrementRelease()InterlockedDecrement() 相同。"

是的,发现并不难:

define InterlockedDecrementRelease _InterlockedDecrement

define InterlockedDecrement _InterlockedDecrement

但仅在x86/x64上才可用。

另外,真实的代码通常应当看起来像

struct SomeStruct 
{
    LONG _count = 1;

    LONG AddRef()
    {
        return InterlockedIncrementNoFence(&_count);
    }

    LONG Release() // Dec
    {
        if (LONG ret = InterlockedDecrement(&_count))
        {
            return ret;
        }
        delete this;
        return 0;
    }
};

当Dec/Release使 _count为 0时,我们需要做点什么。通常是删除对象/调用析构函数等。此外Release至少需要memory_order_acq_rel,而不仅仅是memory_order_release。当AddRef() 可以放宽时。

当一个线程调用AddRef() 时,它必须已经对该对象拥有一个有效引用。既然如此,在该线程接收到该指针时,对对象字段的内存同步已经发生。

计数器的自增仅仅是为了防止其他线程删除对象。这里内存可见性的顺序并不重要。

与此同时,Release() 必须与另一个Release保持一致,而不是与AddRef() 保持一致……一个线程在Release() 之前对对象所写的所有内容,在另一个线程的Release() 之后必须对该线程可见。

这就是需要Acquire + Release(即memory_order_acq_rel)的原因。

尽管这是可行的,甚至更好,以下实现将会是

    LONG Release()
    {
        if (int ret = InterlockedDecrementRelease(&_count))
        {
            return ret;
        }
        MemoryBarrier();
        delete this;
        return 0;
    }
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章