RCU 概念¶
RCU(读取-复制更新)背后的基本思想是将破坏性操作分为两个部分:一部分防止任何人看到正在被破坏的数据项,另一部分实际执行破坏。这两部分之间必须经过一个“宽限期”,并且这个宽限期必须足够长,以便任何访问正在被删除的项目的读者都已经放弃了他们的引用。例如,从链表中受 RCU 保护的删除操作将首先从列表中删除该项,等待一个宽限期过去,然后释放该元素。有关将 RCU 与链表一起使用的更多信息,请参阅 使用 RCU 保护读取为主的链表。
常见问题¶
为什么有人会想使用 RCU?
RCU 两部分方法的优点在于,RCU 读取器无需获取任何锁、执行任何原子指令、写入共享内存,或者(在 Alpha 以外的 CPU 上)执行任何内存屏障。这些操作在现代 CPU 上非常昂贵,这正是 RCU 在读取为主的情况下具有性能优势的原因。RCU 读取器无需获取锁的事实也可以大大简化死锁避免代码。
如果 RCU 读取器没有指示他们何时完成,更新器如何知道宽限期何时完成?
与自旋锁一样,RCU 读取器不允许阻塞、切换到用户模式执行或进入空闲循环。因此,一旦看到 CPU 经过这三种状态中的任何一种,我们就知道该 CPU 已经退出了任何先前的 RCU 读取端临界区。因此,如果我们从链表中删除一项,然后等待所有 CPU 都切换上下文、在用户模式下执行或在空闲循环中执行,我们就可以安全地释放该项。
RCU 的可抢占变体(CONFIG_PREEMPT_RCU)获得相同的效果,但要求读取器操作 CPU 本地计数器。这些计数器允许在 RCU 读取端临界区内进行有限类型的阻塞。SRCU 也使用 CPU 本地计数器,并允许在 RCU 读取端临界区内进行通用阻塞。这些 RCU 变体通过采样这些计数器来检测宽限期。
如果我正在单处理器内核上运行,该内核一次只能执行一件事,我为什么还要等待宽限期?
有关更多信息,请参阅 单处理器系统上的 RCU。
如何查看 Linux 内核中当前使用 RCU 的位置?
搜索“rcu_read_lock”、“rcu_read_unlock”、“call_rcu”、“rcu_read_lock_bh”、“rcu_read_unlock_bh”、“srcu_read_lock”、“srcu_read_unlock”、“synchronize_rcu”、“synchronize_net”、“synchronize_srcu”和其他 RCU 原语。或者从以下位置获取一个 cscope 数据库:
(http://www.rdrop.com/users/paulmck/RCU/linuxusage/rculocktab.html)。
在编写使用 RCU 的代码时,我应该遵循哪些准则?
请参阅 RCU 补丁的审查清单。
为什么叫“RCU”?
“RCU”代表“读取-复制更新”。使用 RCU 保护读取为主的链表 提供了有关此名称来源的更多信息,搜索“read-copy update”即可找到。
我听说 RCU 已获得专利?这是怎么回事?
是的,确实如此。有几个与 RCU 相关的已知专利,在 Documentation/RCU/RTFP.txt 中搜索字符串“Patent”即可找到它们。其中一个专利已被受让人放弃,其他专利已根据 GPL 贡献给 Linux 内核。许多(但并非所有)专利早已过期。现在也有可用的用户级 RCU 的 LGPL 实现 (https://liburcu.org/)。
我听说 RCU 需要进行一些工作才能支持实时内核?
通过 CONFIG_PREEMPTION 内核配置参数启用实时友好的 RCU。
在哪里可以找到有关 RCU 的更多信息?
请参阅 Documentation/RCU/RTFP.txt 文件。或者将您的浏览器指向 (https://docs.google.com/document/d/1X0lThx8OK0ZgLMqVoXiR4ZrGURHrXK6NyLRbeXe3Xac/edit) 或 (https://docs.google.com/document/d/1GCdQC8SDbb54W1shjEXqGZ0Rq8a6kIeYutdSIajfpLA/edit?usp=sharing)。