0001 .. include:: ../disclaimer-zh_CN.rst
0002
0003 :Original: Documentation/core-api/refcount-vs-atomic.rst
0004
0005 :翻译:
0006
0007 司延腾 Yanteng Si <siyanteng@loongson.cn>
0008
0009 .. _cn_refcount-vs-atomic:
0010
0011 =======================================
0012 与atomic_t相比,refcount_t的API是这样的
0013 =======================================
0014
0015 .. contents:: :local:
0016
0017 简介
0018 ====
0019
0020 refcount_t API的目标是为实现对象的引用计数器提供一个最小的API。虽然来自
0021 lib/refcount.c的独立于架构的通用实现在下面使用了原子操作,但一些 ``refcount_*()``
0022 和 ``atomic_*()`` 函数在内存顺序保证方面有很多不同。本文档概述了这些差异,并
0023 提供了相应的例子,以帮助开发者根据这些内存顺序保证的变化来验证他们的代码。
0024
0025 本文档中使用的术语尽量遵循tools/memory-model/Documentation/explanation.txt
0026 中定义的正式LKMM。
0027
0028 memory-barriers.txt和atomic_t.txt提供了更多关于内存顺序的背景,包括通用的
0029 和针对原子操作的。
0030
0031 内存顺序的相关类型
0032 ==================
0033
0034 .. note:: 下面的部分只涵盖了本文使用的与原子操作和引用计数器有关的一些内存顺
0035 序类型。如果想了解更广泛的情况,请查阅memory-barriers.txt文件。
0036
0037 在没有任何内存顺序保证的情况下(即完全无序),atomics和refcounters只提供原
0038 子性和程序顺序(program order, po)关系(在同一个CPU上)。它保证每个
0039 ``atomic_* ()`` 和 ``refcount_*()`` 操作都是原子性的,指令在单个CPU上按程序
0040 顺序执行。这是用READ_ONCE()/WRITE_ONCE()和比较并交换原语实现的。
0041
0042 强(完全)内存顺序保证在同一CPU上的所有较早加载和存储的指令(所有程序顺序较早
0043 [po-earlier]指令)在执行任何程序顺序较后指令(po-later)之前完成。它还保证
0044 同一CPU上储存的程序优先较早的指令和来自其他CPU传播的指令必须在该CPU执行任何
0045 程序顺序较后指令之前传播到其他CPU(A-累积属性)。这是用smp_mb()实现的。
0046
0047 RELEASE内存顺序保证了在同一CPU上所有较早加载和存储的指令(所有程序顺序较早
0048 指令)在此操作前完成。它还保证同一CPU上储存的程序优先较早的指令和来自其他CPU
0049 传播的指令必须在释放(release)操作之前传播到所有其他CPU(A-累积属性)。这是用
0050 smp_store_release()实现的。
0051
0052 ACQUIRE内存顺序保证了同一CPU上的所有后加载和存储的指令(所有程序顺序较后
0053 指令)在获取(acquire)操作之后完成。它还保证在获取操作执行后,同一CPU上
0054 储存的所有程序顺序较后指令必须传播到所有其他CPU。这是用
0055 smp_acquire__after_ctrl_dep()实现的。
0056
0057 对Refcounters的控制依赖(取决于成功)保证了如果一个对象的引用被成功获得(引用计数
0058 器的增量或增加行为发生了,函数返回true),那么进一步的存储是针对这个操作的命令。对存
0059 储的控制依赖没有使用任何明确的屏障来实现,而是依赖于CPU不对存储进行猜测。这只是
0060 一个单一的CPU关系,对其他CPU不提供任何保证。
0061
0062
0063 函数的比较
0064 ==========
0065
0066 情况1) - 非 “读/修改/写”(RMW)操作
0067 ------------------------------------
0068
0069 函数变化:
0070
0071 * atomic_set() --> refcount_set()
0072 * atomic_read() --> refcount_read()
0073
0074 内存顺序保证变化:
0075
0076 * none (两者都是完全无序的)
0077
0078
0079 情况2) - 基于增量的操作,不返回任何值
0080 --------------------------------------
0081
0082 函数变化:
0083
0084 * atomic_inc() --> refcount_inc()
0085 * atomic_add() --> refcount_add()
0086
0087 内存顺序保证变化:
0088
0089 * none (两者都是完全无序的)
0090
0091 情况3) - 基于递减的RMW操作,没有返回值
0092 ---------------------------------------
0093
0094 函数变化:
0095
0096 * atomic_dec() --> refcount_dec()
0097
0098 内存顺序保证变化:
0099
0100 * 完全无序的 --> RELEASE顺序
0101
0102
0103 情况4) - 基于增量的RMW操作,返回一个值
0104 ---------------------------------------
0105
0106 函数变化:
0107
0108 * atomic_inc_not_zero() --> refcount_inc_not_zero()
0109 * 无原子性对应函数 --> refcount_add_not_zero()
0110
0111 内存顺序保证变化:
0112
0113 * 完全有序的 --> 控制依赖于存储的成功
0114
0115 .. note:: 此处 **假设** 了,必要的顺序是作为获得对象指针的结果而提供的。
0116
0117
0118 情况 5) - 基于Dec/Sub递减的通用RMW操作,返回一个值
0119 ---------------------------------------------------
0120
0121 函数变化:
0122
0123 * atomic_dec_and_test() --> refcount_dec_and_test()
0124 * atomic_sub_and_test() --> refcount_sub_and_test()
0125
0126 内存顺序保证变化:
0127
0128 * 完全有序的 --> RELEASE顺序 + 成功后ACQUIRE顺序
0129
0130
0131 情况6)其他基于递减的RMW操作,返回一个值
0132 ----------------------------------------
0133
0134 函数变化:
0135
0136 * 无原子性对应函数 --> refcount_dec_if_one()
0137 * ``atomic_add_unless(&var, -1, 1)`` --> ``refcount_dec_not_one(&var)``
0138
0139 内存顺序保证变化:
0140
0141 * 完全有序的 --> RELEASE顺序 + 控制依赖
0142
0143 .. note:: atomic_add_unless()只在执行成功时提供完整的顺序。
0144
0145
0146 情况7)--基于锁的RMW
0147 --------------------
0148
0149 函数变化:
0150
0151 * atomic_dec_and_lock() --> refcount_dec_and_lock()
0152 * atomic_dec_and_mutex_lock() --> refcount_dec_and_mutex_lock()
0153
0154 内存顺序保证变化:
0155
0156 * 完全有序 --> RELEASE顺序 + 控制依赖 + 持有