18

Herb Sutter在他的博客中写道

[...] 因为增加智能指针引用计数 通常可以优化为与优化shared_ptr实现中的普通增量相同——在生成的代码中只是一条普通的增量指令,没有栅栏。

但是,减量必须是原子减量或等效物,它会生成特殊的处理器内存指令,这些指令本身更昂贵,并且在此之上会导致内存栅栏限制优化周围代码。

文本是关于实施的shared_ptr,我不确定他的评论是否仅适用于此或一般情况下。从他的表述中,我推测它是一般的。

但是当我想到它时,我只能在if(counter==0)紧随其后想到“更昂贵的减量”——这可能是shared_ptr.

因此,我想知道原子操作++counter是否(通常)总是比快--counter还是仅仅因为if(--counter==0)...shared_ptr?

4

3 回答 3

16

他在某处更详细地讨论了这一点,我认为在他的atomic<> 武器演示中。基本上,这都是关于在 shared_ptr 用例中需要内存栅栏的地方,而不是原子增量与减量的任何内在属性。

原因是您并不真正关心使用 ref 计数的智能指针的增量的确切顺序,只要您不会错过任何内容,但是减量时,您必须设置内存屏障,以便在最终减量时这会触发删除,您不可能在释放内存后从另一个线程对智能指针拥有的对象进行先前的内存访问。

于 2013-06-06T16:10:58.463 回答
11

我相信它指的是增量可以“隐藏”,其中“减量和检查”必须作为一个操作完成。

我不知道有任何架构--counter(或者counter--,假设我们正在谈论简单的数据类型,如 int、char 等)比++counteror慢counter++

于 2013-06-06T15:31:23.160 回答
10

Sutter 正在谈论的问题是引用计数增量不需要任何后续操作来确保正确性。您将一个非零引用计数转换为另一个非零计数,因此不需要进一步的操作。但是,减量需要后续操作才能正确。递减将非零引用计数变为非零或零引用计数,如果您的引用计数递减为零,您需要执行一个操作 --- 具体来说,释放引用的对象。这种递减和执行动态需要更高的一致性,无论是在栅栏级别(因此释放不会与 CPU 的内存/缓存管理逻辑重新排序的另一个内核上的其他读/写一起重新排序)和在编译器级别(所以编译器不'

因此,对于 Sutter 所描述的场景,增量和减量之间的成本差异不在于基本操作本身,而在于对减量的实际使用(特别是作用于减量本身)施加的一致性约束,而不是适用于增量。

于 2013-06-06T16:23:10.927 回答