refcount_t API 与 atomic_t 的比较 【ChatGPT】

发布时间 2023-12-09 19:54:30作者: 摩斯电码

refcount_t API 与 atomic_t 的比较

介绍

相关的内存排序类型

函数比较

  1. 非“读/修改/写”(RMW)操作

  2. 基于增量的操作,不返回值

  3. 基于减量的 RMW 操作,不返回值

  4. 基于增量的 RMW 操作,返回值

  5. 通用的减法/减量基于 RMW 操作,返回值

  6. 其他基于减量的 RMW 操作,返回值

  7. 基于锁的 RMW

介绍

refcount_t API 的目标是为实现对象的引用计数器提供一个最小的 API。虽然 lib/refcount.c 中的通用体系结构无关实现使用原子操作,但是在一些 refcount_() 和 atomic_() 函数之间存在一些差异,涉及内存排序保证。本文档概述了这些差异,并提供了相应的示例,以帮助维护者验证其代码针对这些内存排序保证的变化。

本文档中使用的术语试图遵循 tools/memory-model/Documentation/explanation.txt 中定义的正式 LKMM。

memory-barriers.txt 和 atomic_t.txt 提供了更多关于内存排序的背景知识,特别是针对原子操作。

相关的内存排序类型

注意
以下部分仅涵盖了原子操作和引用计数器相关的一些内存排序类型,并在本文档中使用。要了解更广泛的情况,请参阅 memory-barriers.txt 文档。

在没有任何内存排序保证的情况下(即完全无序),原子操作和引用计数器仅提供原子性和程序顺序(po)关系(在同一 CPU 上)。它保证每个 atomic_() 和 refcount_() 操作都是原子的,并且指令在单个 CPU 上按程序顺序执行。这是使用 READ_ONCE()/WRITE_ONCE() 和比较交换原语实现的。

强(完全)内存排序保证了在同一 CPU 上所有先前的加载和存储(所有 po-更早的指令)在执行同一 CPU 上的任何 po-后续指令之前完成。它还保证了在同一 CPU 上所有先前的存储和来自其他 CPU 的所有传播存储必须在原始 CPU 上执行任何 po-后续指令之前传播到所有其他 CPU(具有累积属性)。这是使用 smp_mb() 实现的。

RELEASE 内存排序保证了在同一 CPU 上所有先前的加载和存储(所有 po-更早的指令)在操作之前完成。它还保证了在同一 CPU 上所有先前的存储和来自其他 CPU 的所有传播存储必须在释放操作之前传播到所有其他 CPU(具有累积属性)。这是使用 smp_store_release() 实现的。

ACQUIRE 内存排序保证了在同一 CPU 上所有后续的加载和存储(所有 po-后续指令)在获取操作之后完成。它还保证了在同一 CPU 上所有后续的存储在获取操作执行后必须传播到所有其他 CPU。这是使用 smp_acquire__after_ctrl_dep() 实现的。

对于引用计数器的成功控制依赖性保证了如果成功获取对象的引用(引用计数增加或添加发生,函数返回 true),则进一步的存储将按顺序执行。对于存储的控制依赖性不是使用任何显式的屏障实现的,而是依赖于 CPU 不对存储进行推测。这仅是单个 CPU 关系,并且不对其他 CPU 提供任何保证。

函数比较

  1. 非“读/修改/写”(RMW)操作

    函数变更:

    • atomic_set() --> refcount_set()
    • atomic_read() --> refcount_read()

    内存排序保证变更:

    • 无(均完全无序)
  2. 基于增量的操作,不返回值

    函数变更:

    • atomic_inc() --> refcount_inc()
    • atomic_add() --> refcount_add()

    内存排序保证变更:

    • 无(均完全无序)
  3. 基于减量的 RMW 操作,不返回值

    函数变更:

    • atomic_dec() --> refcount_dec()

    内存排序保证变更:

    • 完全无序 --> RELEASE 排序
  4. 基于增量的 RMW 操作,返回值

    函数变更:

    • atomic_inc_not_zero() --> refcount_inc_not_zero()
    • 无原子对应项 --> refcount_add_not_zero()

    内存排序保证变更:

    • 完全有序 --> 成功时对存储进行控制依赖

    注意

    我们在这里真的假设获得对象指针时提供了必要的排序!

  5. 通用的减法/减量基于 RMW 操作,返回值

    函数变更:

    • atomic_dec_and_test() --> refcount_dec_and_test()
    • atomic_sub_and_test() --> refcount_sub_and_test()

    内存排序保证变更:

    • 完全有序 --> RELEASE 排序 + 成功时的 ACQUIRE 排序
  6. 其他基于减量的 RMW 操作,返回值

    函数变更:

    • 无原子对应项 --> refcount_dec_if_one()
    • atomic_add_unless(&var, -1, 1) --> refcount_dec_not_one(&var)

    内存排序保证变更:

    • 完全有序 --> RELEASE 排序 + 控制依赖

    注意

    atomic_add_unless() 仅在成功时提供完全排序。

  7. 基于锁的 RMW

    函数变更:

    • atomic_dec_and_lock() --> refcount_dec_and_lock()
    • atomic_dec_and_mutex_lock() --> refcount_dec_and_mutex_lock()

    内存排序保证变更:

    • 完全有序 --> RELEASE 排序 + 控制依赖 + 成功时持有 spin_lock()