RCU是linux 2.6 kernel实现的一种高效的同步机制,适用于读者多,写者少的情况。它的适用场合和读写锁是很相似的。但是和读写锁来比,它可以提高了读者的效率。因为使用RCU的读者在访问共享数据的时候不需要加锁,而使用读写锁的读者则需要加读锁,在多CPU环境中会有高速缓存行失效的问题,所以效率稍低。
但是没有天下没有免费的午餐。RCU有它自身的缺点和使用限制。首当其冲的缺点就是写者的效率问题,RCU要求写者在更新共享数据的时候,先拷贝一份,修改,然后在更新,写者做了太多事情,所以效率低。另外RCU有两个使用限制条件:
. RCU只保护动态分配并通过指针引用的数据结构
. 在被RCU保护的临界区中,任何内核路径都不能睡眠
明白了为什么有这两个限制,也就明白了RCU的实现原理。
第一个限制条件是因为对指针变量的修改是原子操作,这样读者读这个指针和写者修改这个指针的操作就不需要同步。写者在操作的时候首先定义一个新指针,申请空间,然后拷贝原指针指向的内容,修改完毕后,直接将刚申请的新指针的值赋给共享指针。这样也就要求读者在访问的时候,需要先定义另外一个指针,然后将共享指针的值赋给新指针,然后用新指针进一步访问里面的内容,不能直接使用共享指针访问其中的内容,因为如果那样,在读者两次访问共享指针指向的内容的中间,共享指针的值可能被写者改变,造成数据不一致的问题。
第二个限制条件是因为被写者替换前的指针指向的空间必须被释放,而且这个释放必须是在所有进程都已经不在引用旧指针的基础上。加上这个限制就可以通过进程切换来判断了,只要某个CPU进程切换过一次,就知道这个CPU上已经不存在引用旧数据的进程了,如果所有CPU在写者更新以后都进行过至少一次进程切换,那么旧的数据就可以被释放掉了。另外这个限制也要求读者在访问共享指针前要禁用内核抢占,否则可能发生进程切换。