RCU概览

RCU是一种同步机制,在2.5开发时加入到Linux内核中,针对以读取为主的情况进行了优化。虽然RCU非常简单,但是实现是一个挑战。可以通过本文(摘自kennel文档)以及源代码(更直接和实际)来了解掌握。

原理

RCU 背后的基本思想是将更新分为 “删除” (removal) 和 “回收” (reclamation) 阶段:

  • 删除阶段删除对数据结构内的数据项的引用(可能通过将它们替换为对这些数据项的新版本的引用),并且可以与读取器同时运行

    • 与reader同时运行删除阶段是安全的原因是: 现代 CPU 的语义保证 reader 将看到旧版本或新版本的数据结构,而不是部分更新的引用

  • 回收阶段进行 回收(例如,释放)在删除阶段从数据结构中删除的数据项的工作

    • 由于回收数据项可能会中断同时引用这些数据项的任何 reader ,因此在 reader 不再持有对这些数据项的引用之前,回收阶段不得开始 (我是不是可理解为类似文件句柄,如果文件句柄还在使用,不应该删除文件)

将更新分为删除和回收阶段允许更新程序立即执行删除阶段,并推迟回收阶段,直到删除阶段期间所有活动的reader完成为止:

  • 方法是阻塞直到完成或注册在完成后调用的回调

  • 因为在删除阶段之后启动的任何读取器都将无法获得对已删除数据项的引用,因此不会被回收阶段中断

典型的 RCU 更新顺序如下:

  • 删除指向数据结构的指针,以便后续读取者(readers)无法获得对其的引用

  • 等待所有先前的读取者(readers)完成其 RCU 读取端关键部分

  • 此时,不可能有任何读取者(readers)持有对该数据结构的引用,因此现在可以安全地回收它(例如, kfree()

等待所有读取器完成的能力允许 RCU 读取器使用更轻量级的同步,在某些情况下,完全不同步

相反,在更传统的基于锁的方案中,读取器必须使用重量级同步,以防止更新者删除它们下面的数据结构

基于 RCU 的更新程序通常利用这样一个事实 ,即在现代 CPU 上写入单个对齐指针是原子的,允许原子插入、删除和替换链接结构中的数据项,而不会中断读取器。然后,并发 RCU 读取器可以继续访问旧版本,并且可以省去原子操作、内存屏障和通信高速缓存未命中,这些操作在当今的 SMP 计算机系统上非常昂贵,即使在没有锁争用的情况下也是如此。

备注

更进一步理解需要阅读源码和实践编码,待续

参考