引用计数指针指向平凡可析构类型时,memory_order_acquire是否多余?
关于平凡可析构类型引用计数中acquire栅栏的作用分析
你的问题抓得非常准——针对平凡可析构类型,这个memory_order_acquire栅栏看起来确实有点“多余”,咱们一步步拆解验证你的思路:
首先先回顾原代码逻辑:
if (x->refcount_.fetch_sub(1, boost::memory_order_release) == 1) { // A boost::atomic_thread_fence(boost::memory_order_acquire); delete x; }
先明确核心概念
- 平凡可析构类型:比如
int这类内置类型,或者用户定义但析构函数为平凡(无自定义逻辑、仅默认释放内存)的类型。它们的delete操作本质只是把内存归还给分配器,不会读取或依赖对象本身的任何状态。 - 原逻辑中acquire栅栏的初衷:对于非平凡可析构类型(比如带自定义析构函数的类),栅栏的作用是确保当前删除线程能看到
x指向对象的所有最新修改——毕竟自定义析构可能会依赖对象的状态(比如关闭句柄、清理内部缓存等),如果看不到最新值,析构逻辑可能出错。
针对平凡可析构类型的分析
你的思路基本是正确的:
- 因为平凡可析构类型的
delete操作完全不依赖对象的内容——不管删除线程看到的*x是最新值还是旧的缓存值,delete的行为都是一模一样的:仅回收内存,不会对对象内容做任何读取或操作。 - 再加上
fetch_sub用了memory_order_release,已经保证了所有其他线程对x指向对象的修改,都不会被重排到这个引用计数递减操作之后,也就是说后续不会有线程再修改这个对象了。
为什么库实现通常还是保留这个栅栏?
虽然功能上可以省略,但像Boost这类库会统一保留这个栅栏,原因有两个:
- 代码通用性:不需要针对“平凡/非平凡可析构”做分支判断,避免因类型判断错误导致的隐蔽bug;
- 性能代价极低:现代CPU的内存栅栏开销非常小,几乎可以忽略不计,保留它不会带来明显的性能损失。
总结
对于平凡可析构类型,这个memory_order_acquire栅栏确实不会影响程序的正确性——你的判断没问题。但从代码健壮性和库实现的简洁性角度,保留它是更稳妥的选择。
内容的提问来源于stack exchange,提问作者Saddie
相关产品推荐
相关产品推荐

