在他的Blog Herb Sutter写道
中[...]因为增加智能指针引用次数 通常可以优化为与普通增量相同 在优化的
shared_ptr
实现中 - 只是一个普通的增量指令, 生成的代码中没有围栏。然而,减量必须是原子减量或等价物, 它生成更昂贵的特殊处理器内存指令 他们自己,而且最重要的是诱导记忆 围栏限制优化周围的代码。
该文本是关于shared_ptr
的实施,我不确定他的评论是否只适用于此或通常是这样。根据他的提法我收集的是一般。
但是当我想到它时,我只能在if(counter==0)
紧随其后的时候想到“更昂贵的减量” - 这可能是shared_ptr
的情况。
因此,我想知道原子操作++counter
是否(通常)总是比<{1}} 1>更强,或仅仅因为 --counter
使用if(--counter==0)...
?
答案 0 :(得分:16)
他在某个地方更详细地讨论了这一点,我想在他的atomic<> weapons演讲中。基本上所有关于shared_ptr用例中需要内存栅栏的地方,而不是原子增量与减量的任何内在属性。
原因是你并不真正关心使用引用计数智能指针的增量的确切顺序,只要你不会错过任何一个,但是随着减量,你必须有内存屏障才能这样做你的最终减量触发了删除你没有任何可能的事情,从另一个线程到内存被释放后被重新排序的智能指针拥有的对象的先前内存访问。
答案 1 :(得分:11)
我认为它指的是增量可以“隐藏”,其中“减量和检查”必须作为一个操作完成。
我不知道任何架构--counter
(或counter--
,假设我们讨论的是简单数据类型,如int,char等)比++counter
或{更慢} {1}}。
答案 2 :(得分:9)
Sutter所讨论的问题是引用计数增量不需要任何后续操作来保证正确性。您将非零引用计数转换为另一个非零计数,因此无需进一步操作。但是,减量需要采取后续行动以确保正确性。递减将非零引用计数引用为非零或零引用计数,如果引用计数的减量变为零,则需要执行操作 - 具体而言,取消分配引用的对象。这种递减和动作动态需要更高的一致性,在栅栏级别(因此解除分配不会与CPU的内存/缓存管理逻辑重新排序的另一个核心上的某些其他读/写重新排序)和编译器级别(因此编译器不会对可能导致读取/写入在潜在释放周围重新排序的减量重新排序操作)。
因此,对于Sutter描述的场景,增量和减量之间的成本差异不在于基本操作本身,而是在对减量的实际使用施加的一致性约束中(具体地,对减量本身起作用)不适用于增量。