Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 原子decref实现之间的差异_C++_C_Atomic_Reference Counting_Memory Model - Fatal编程技术网

C++ 原子decref实现之间的差异

C++ 原子decref实现之间的差异,c++,c,atomic,reference-counting,memory-model,C++,C,Atomic,Reference Counting,Memory Model,我一直在研究原子引用计数的实现 大多数操作在库之间是非常一致的,但我在“减少引用计数”操作中发现了令人惊讶的变化。(请注意,通常情况下,共享和弱decref之间的唯一区别是调用了_zero()上的。例外情况如下所示。) 如果有其他实现是根据C11/C++11模型实现的(MSVC做什么?),而不是“我们使用seq_cst,因为我们不知道更好的”类型,请随意编辑它们 大多数例子最初是C++,但是这里我已经把它们重写成C,内联和规范化到 = 1 约定: #include <stdatomic.h

我一直在研究原子引用计数的实现

大多数操作在库之间是非常一致的,但我在“减少引用计数”操作中发现了令人惊讶的变化。(请注意,通常情况下,共享和弱decref之间的唯一区别是调用了_zero()上的
。例外情况如下所示。)

如果有其他实现是根据C11/C++11模型实现的(MSVC做什么?),而不是“我们使用seq_cst,因为我们不知道更好的”类型,请随意编辑它们

大多数例子最初是C++,但是这里我已经把它们重写成C,内联和规范化到<代码> = 1 约定:

#include <stdatomic.h>
#include <stddef.h>
typedef struct RefPtr RefPtr;
struct RefPtr {
    _Atomic(size_t) refcount;
};
// calls the destructor and/or calls free
// on a shared_ptr, this also calls decref on the implicit weak_ptr
void on_zero(RefPtr *);
对于fetch_子操作,可以使用memory_order_acq_rel,但当参考计数器尚未达到零时,这会导致不必要的“获取”操作,并可能会造成性能损失

但大多数其他人( , , )做点别的:

void decref_common(RefPtr *p) {
    if (atomic_fetch_sub_explicit(&p->refcount, 1, memory_order_acq_rel) == 1)
        on_zero(p);
}
但libc++确实如此。奇怪的是,这是在一个外部源文件中:

void decref_libcxx_weak(RefPtr *p) {
    if (atomic_load_explicit(&p->refcount, memory_order_acquire) == 1)
        on_zero(p);
    else
        decref_common(p);
}

那么,问题是:实际的区别是什么

子问题:评论有错吗?具体的平台做什么(在AARC64上,
ldar
会比
dmb ishld
便宜吗?同样是ia64?)?在什么条件下可以使用较弱的版本(例如,如果dtor是nop,如果删除程序只是
免费的
,…)


另请参见和

源代码中记录了libc++选项:

注意:此处的获取负载是对 共享指针在运行时被销毁的常见情况 没有其他有争议的参考文献


libc++编码器观察到,大多数情况下,当最后一个
共享的ptr
被销毁时,没有
弱的ptr
引用共享对象。据我所知,至少在x86上,读-修改-写指令比读指令扩展得多。因此,对于最常见的情况,他们决定避免执行扩展的、未使用的读-修改-写操作。标准库的其他实现不执行此优化。

仅无条件地执行
发布
和有条件地执行
获取
可能是一种性能优势,但我怀疑很多
共享的\u ptr
都只有一个引用,因此,分支预测器将接受训练,以推测性地执行
acquire
。如果有一条有效的指令用于
原子取数子显式(acq\u rel)
,那么组合运算会更好。@如果你猜大多数
共享ptr
都被用作重的、相对复杂的、类型擦除的
唯一的\u ptr
?@curiousguy我不会感到惊讶。为什么不呢?大多数情况下,
shared\u ptr
的低效不会成为速度方面的瓶颈,所以在它出现在个人资料中之前,谁在乎呢?@curiousguy我不是说你不应该在适当的地方使用
unique\u ptr
,我是说它可能没有得到一致的使用,当然,创建的库代码不知道多个所有者或单个所有者是否适合用户,这正是为什么它应该总是返回一个
唯一的\u ptr
.Hm,但该代码适用于所有的弱点,如果是内联的,则可以避免额外的测试。另外,评论是谎言。@o11c从我所看到的,当一组表达式涉及原子表达式时,优化实际上是被禁用的。@curiousguy确实,为了好玩,看看那个恐怖:!!!!!原子被视为挥发性原子。原子负荷的概念和副作用的概念之间存在混淆。标准对此很清楚。仍然有人鼓吹挥发性原子是没有意义的。这些说教持续了这么长时间,我们可以预期这种代码悲观主义将永远存在@奥利夫:很有趣。谁制定了这些规则?@Oliv如果这是一个
acquire
load,那么删除它是不合法的,对吗?
void decref_libcxx_weak(RefPtr *p) {
    if (atomic_load_explicit(&p->refcount, memory_order_acquire) == 1)
        on_zero(p);
    else
        decref_common(p);
}