嵌入式Linux——rcu_read_lock() 到底在 “lock“ 什么?—— 理解 RCU 读端的真正代价
·
问题理解
- 关于RCU 读-复制-更新,这类锁我有点不理解的是为什么已经说了RCU不同于自旋锁,使用RCU的读端没有锁、内存屏障、原子指令类的开销,那为什么还要用
rcu_read_lock()和rcu_read_unlock()函数呢? rcu_read_lock()和rcu_read_unlock()到底是在做什么?
名字误导
rcu_read_lock()和rcu_read_unlock()可能是 Linux 内核中命名最具有误导性的函数之一。- 它们并不是“锁”(in the sense of a spinlock or mutex)。
- 它不会让任何人在等待中“自旋”(spin)。
- 它不会导致睡眠或上下文切换。
- 它不会阻止其他 CPU 上的读或写操作。
- 它不会执行昂贵的原子操作或内存总线同步。
rcu_read_lock() 真正的工作
- 它真正的、也是唯一的工作是:充当一个“标记”,告知 RCU 系统:“这个 CPU 现在正处于 RCU 读临界区”。
- 在绝大多数“经典”的 Linux 内核实现中 (例如 PREEMPT_RCU),这两个函数做的事情极其简单:
rcu_read_lock() -> preempt_disable()(禁用内核抢占)rcu_read_unlock() -> preempt_enable()(恢复内核抢占)
为什么要禁用内核抢占?
- 这解决了我们问题的核心:既然 RCU 这么快,为什么还需要做“禁用抢占”这个动作?
- 我们必须理解 RCU 更新的“契约”是什么。RCU 的写端(更新者)在删除旧数据时,必须等待一个所谓的“宽限期” (Grace Period) 结束。
- “宽限期”的定义是:等待所有 CPU 都至少发生过一次“上下文切换”或“进入空闲”。(这被称为“静止状态”,Quiescent State)。
- RCU 系统以此来保证:只要宽限期结束,那么所有在宽限期开始前 就已经 在读取旧数据的 CPU,现在 一定 已经读取完毕了。
举例
- 现在,假设没有
rcu_read_lock():- CPU 0 开始读取一个 RCU 保护的数据 p。(比如
my_data = p->value;) - 刚执行完
my_data = p->value;,CPU 0 发生“内核抢占”(比如一个更高优先级的任务来了),当前任务被换下。 - CPU 1 (写端) 此时发起一个更新,它用
p_new替换了p,并要求系统在宽限期后释放p(旧数据)。 - 宽限期开始…
- 系统检测到所有 CPU(包括 CPU 0)都发生了上下文切换(因为 CPU 0 刚刚在第 2 步被抢占了)。
- 宽限期结束! RCU 系统认为:“所有 CPU 都已经‘登记’过了,现在释放
p是安全的。” - p 的内存被释放。
- …过了很久…
- CPU 0 上的那个被抢占的任务终于被调度回来了。它继续执行
rcu_read_lock临界区里的下一行代码,比如next_value = p->next; - BOOM! 💥
p已经被释放了。CPU 0 访问了一个“野指针”,导致系统崩溃(Use-After-Free)。
- CPU 0 开始读取一个 RCU 保护的数据 p。(比如
如何解决的
rcu_read_lock()(即preempt_disable()) 如何解决这个问题:rcu_read_lock()禁用了抢占。- CPU 0 在读取 p 期间,绝不可能被其他任务抢占。
- 它必须执行完
rcu_read_unlock()(即preempt_enable()) 之后,才可能发生上下文切换。 - RCU 的宽限期必须等到 CPU 0 执行完
rcu_read_unlock()并真正发生上下文切换后,才能结束。 - 这就保证了,只要
rcu_read_lock()临界区还没有退出,宽限期就一定不会结束,旧数据 p 就一定不会被释放。
这是否违背了“零开销”的承诺
- 完全没有!这也正是 RCU 设计的精妙之处。
preempt_disable()和preempt_enable()的开销是什么?- 在大多数架构上,它只是修改当前 CPU 的一个本地变量(比如
preempt_count计数器)。它不需要昂贵的原子操作,更不需要和任何其他 CPU 通信。这个开销几乎为零,比一个 spin_lock()(需要总线锁定的原子cmpxchg)快了几个数量级。 - 所以,我们最初的理解是对的: RCU 读端确实没有“锁、内存屏障、原子指令”(在“与其他 CPU 同步”的意义上)。它所做的
rcu_read_lock(),只是一个极其廉价的“本地标记”(禁用抢占),用于和 RCU 的垃圾回收机制(宽限期)进行“沟通”。
更多推荐
所有评论(0)