RCU (Read-Copy-Update)
RCU 是一种读写锁的替代方案,主要针对以读为主的 workload,它的思路是:
- writer 要更新被保护的对象的时候,不修改已有的对象,而是生成一个新的 copy,然后原子地进行对象引用的替换;那么 reader 此时依然可以正常访问对象,只不过可能访问的是修改前的版本,也可能访问的是修改后的版本
- writer 如果要删除某个对象,首先把对这个对象的引用修改掉,使得未来的 reader 不会再访问该对象;然后等待所有正在进行的 reader 完成它们的读取,此时这个对象一定没有 reader 在访问,于是可以进行回收
- 如果有多个 writer,那么 writer 之间依然需要用互斥锁保护,保证只有一个 writer 同时在修改
Linux 内核中的 RCU
reader 一侧要做的事情:
- 调用
rcu_read_lock()
,表示 reader 读取对象的区间的开始 - 使用
rcu_dereference(pointer)
来对指针进行解引用 - 调用
rcu_read_unlock()
,表示 reader 读取对象的区间的结束
writer 一侧要做的事情:
- 如果是多个 writer,首先获取互斥锁:
spin_lock(mutex)
- 调用
rcu_dereference_protected()
来对指针进行解引用,得到原值 - 调用
kmalloc()
以创建新的对象,再基于上一步读取的原值进行修改 - 调用
rcu_assign_pointer()
把指针指向新的对象 - 如果是多个 writer,释放互斥锁:
spin_lock(mutex)
- 调用
synchronize_rcu()
等待所有正在进行的 reader 完成读取(即调用rcu_read_unlock
) - 调用
kfree
把原来的旧对象释放掉
参考: