从what ,why, howto,原理,优缺点,注意事项,适用对象,这几个角度来说说。
RCU的实现还是比较精巧的。
what什么是RCU.
Read-copy update (RCU) is a synchronization mechanism that was added to the Linux kernel in October of 2002
本质是一种同步优化。但是不同于rwlock读写锁。实现上很有技巧。
RCU顾名思义就是读-拷贝修改。
就这个名字就有些说头:
读者R就是随便你read。
写者CU拷贝修改,网上有人说:“最后使用一个回调(callback)机制在适当的时机把指向原来数据的指针重新指向新的被修改的数据”。我想这个说法应该是错误的。
应该是写者CU之后写者就立刻马上更新了指针(RCU中叫发布)。新的读者R通过(订阅)能得到一个有效的数据(可能是旧的),只要它已经发布了,读者R就可能
立刻得到新指针。比如RCU保护区间内,读者R疯狂的不停的多次引用数据指针,如果同时写者疯狂的更新CU并发布,读者R完全可以读到多个不同的数据指针。
其所谓的适当时机,不过是把旧的数据块可以安全销毁free。理解这点非常关键,老实讲,我之前就被这句误导了,这句话有明显的欺骗性,因为它能自圆其说。
why RCU?
为什么要用RCU,使用场景是啥?
>多读少写/更新的场景比较适合。(其实吧,完全可以多读多写,因为多写了(一次操作中写多几个其开销并不比少写多了什么开销)
比如像路由表,表很大,查询的时候多,真正更新的情况少。像LSM这要安全回调函数,如何安全高效的增换新回调函数? 内核热patch是不是也可以用RCU的机制?
适用对象:
对于旧数据不是那么敏感。指针引用的数据块,list,hlist这两种链表。
howto,原理
从实现原理上讲,它本身是依赖了CPU硬件特性:指针更新是一个原子操作。一个重要原因是RCU的效率要求决定:是不能获得任何锁实现自己,如果这样它就退化了。
也就是对于读reader来说,它是不需要获得锁就能访问被RCU保护的数据,也就是一种无锁的实现,lockless的并发访问方法。随你读写。
经典RCU实现很有技巧:
1.本质上有一个问题要解决:何时可以free旧数据块。在设计上有一种极端的情况就是reader可能会one by one一直不间断的出现,如果等所有的reader都退出时释放在设计上是不可接受(事实上可接受)。RCU的一个重要优化就是:不用等所有的reader都退出,只要在一个宽限期内所有CPU上的reader退出即可。在synchronize_rcu()调用开始的点上,所有CPU上的reader至多有N个(也就是CPU online核数)。这N个reader在rcu_read_lock()/rcu_read_unlock()的保护段退出后,宽限期就同时结束。这样最坏的宽限期是有限的。这N个reader退出就表示所引用的旧数据将可以安全释放。
2.经典RCU实现在处理宽限期是通过CPU调度的切换来判断的,rcu_read_lock()会关掉抢占,rcu_read_unlock()会打开抢占,允许调度切换。这个实现本身是精巧的,但是
要求在rcu_read_lock时不能睡眠,还要快。有点中断处理函数的意思。不过了,有改进型,像srcu,是可以睡眠阻塞。
参考资料:
[1] https://lwn.net/Articles/262464/ What is RCU, Fundamentally?
[2] https://blog.csdn.net/andylauren/article/details/70233241 深入理解 RCU 实现