Day25 RCU 同步机制

前言

前几天介绍了 mutex, semaphore, spinlock, read-write lock, 这些锁有着各式各样的功能,为什麽还要单独设计一种新机制取代现有的这些锁,甚至这个新机制的运作比过往的锁都还要复杂,让我们继续看下去

RCU(Read-Copy Update, RCU)

相比於过去的同步机制,包含 mutex, semaphore, spinlock 等,这些已知的锁都是使用了最小操作(atomic operation),因此在多CPU争抢共享变数时会让缓冲记忆体的一致性变得很糟糕,造成 cache bouncing,让整体效能降低。因此RCU 想要做到的事情是让读取的执行序再也没有为了同步所产生的效能损耗,或者让损耗变得很小,甚至可以忽略不计,也不用有额外的锁,不需要 atomic operation和记忆体屏障,就可以顺利的访问资料。
RCU 适用於频繁的读取 (即多个 reader)、但资料写入 (即少量的 updater/writer) 却不频繁的情境,并且对资料的一致性没有强烈的要求,像是如果有多个执行绪同时要读取某个链表上的节点,如果有执行绪对该节点写入,可以接受有些执行绪读取到新的值,有些执行绪读取到旧的值。
以下这张图是比较 rw-lock 与 RCU 机制在资料被更新时的差异,绿色代表开始读取到updater更新过的新值。
上半部的图是 rw-lock 进行同步,可以看见当收到更新资料的请求时, writer 必须要等到三个reader都停止读取之後才能够写入,在那之前writer 必须要spin;在writer更新的时候,reader也没办法做其他事情,只能spin等待写入的完成。
下半部的图是使用 RCU 进行同步,可以发现收到update 的虚请求之後,RCU updater马上开始运转,reader也是能够持续读取,直到 updater完成之後,新加入的reader就可以读取到新的值了。

以下用一个链表作为例子,分为四个步骤

  1. 初始状态
  2. 收到update请求,开始进行更新
  3. update完成,新reader 读取新资料
  4. 就资料的reader皆已结束,回收旧node。

以下列出几个RCU 常用的API :
rcu_read_lock()/rcu_read_unlock() : 组成一个read的RCU C.S。
rcu_dereference(): 获取被RCU保护的指针,reader 执行绪为了访问RCU保护的共享资料,需要使用此函数创立一个新的指针,并且指向RCU保护的资料。
rcu_assign_pointer() :用於写入执行绪,在写入新数据後,使用此函数可以让RCU保护的指针指向新建立的函数,换句话说就是发布更新後的资料,如同上图的步骤三。
synchronize_rcu() : 等待所有现存的读取访问完成,准备将旧资料删除。
call_rcu() :注册一个callback函数,当线存的读取访问完成後,使用这个函数销毁数据。

在Linux kernel中, <Documents/RCU>里面有许多跟RCU有关的资料,如果之後有时间,我会去多加研究。

Linux 核心设计: RCU 同步机制

ref


<<:  Day 25 - redux-saga 文件范例

>>:  # Day25--还不Merge一下?

DAY30 - 完赛心得与下一步

第一次参加铁人赛,原本以为超前部署,开赛前两个星期就开始准备文章存档 本以为一定妥当的啦,没想到後面...

鬼故事 - 这不是後门这是工程模式!

鬼故事 - 这不是後门这是工程模式! Credit: sandserif 故事开始 故事回到小弯的公...

【Day21】:客制化的PWM输出

客制化PWM 这里所说的客制化PWM指的就是我们可以输出任何想要的方波波形,例如输出10个完整的波後...

前导文 - 科学不能解决大自然的奥秘(↑订阅)

「鲑鱼均,因为一场鲑鱼之乱被主管称为鲑鱼世代,广义来说以年龄和脸蛋分类的话这应该算是一种 KNN 的...

Day12 - 辨识模型 part1

完成了第一阶段的除噪模型之後,接下来要进入辨识阶段,利用乾净状态资料和降噪後的含有噪音的训练资料来训...