一、RCU简介
Read-Copy-Update(RCU)是一种应用在并发多线程环境下的读写锁算法。相较于传统的读写锁,RCU提供了更佳的并发度,提高了读取操作的效率,并降低了写入操作的开销。
在操作系统中,RCU是由Linux内核开创性地引入并应用的。自Linux 2.5起,RCU就已经在内核中得到了应用。随着处理器核数的增加,RCU优势已经日益显著。
RCU实现一个简单的思想是:读者和写者之间并行,读者只需要等待写者完成更新,而不是像传统的读写锁要求等待读锁或写锁时相互竞争。当读者正在读取访问共享资源时,写者会从旧数据开始写入更新的数据到一个新的内存块,而不会覆盖旧内存块中的数据。
二、RCU基本操作
RCU基本原理是在写入时暂停读取,使所有读者可以在不安排竞争的情况下读取共享数据。但在读取期间执行写操作时,需要确保读取操作始终引用有效数据或完全忽略写入结果,这是通过使用一组RCU API完成的。
1. rcu_read_lock()
void rcu_read_lock(void);
rcu_read_lock用于以RCU方式添加执行读取操作所需的读取保护。RCU读取保护是RCU读取地图中的一个进程计数器,类似于Linux中递归读取锁。调用rcu_read_lock将该进程置于正在进行RCU读取的进程列表中,并递增RCU读取地图上的进程计数器。rcu_read_lock不能被递归调用。
2. rcu_read_unlock()
void rcu_read_unlock(void);
rcu_read_unlock在执行RCU读操作完成后释放RCU读取保护。这将递减RCU读取地图中的进程计数器,以指示该进程已完成RCU读取并且已不再使用共享数据。调用rcu_read_unlock不能被忘记或递归调用。
三、RCU_BJ的使用
RCU_BJ是一种特定于Linux内核的RCU实现,它实现了Bhattacharya、Jonathan和Kashyap的发布机制。RCU_BJ提供RCU API,可用于控制在读取时使用RCU;不需要任何其他锁定机制。
1. rcu_barrier()
void rcu_barrier(void);
rcu_barrier用于确保任何RCU读取保护都已释放或等待。该功能等待后台工作作业完成,以确保所有之前执行的rcu_read_unlock已经完成且rcu_read_lock未再加锁。
2. rcu_assign_pointer()
void rcu_assign_pointer(datap, ptr);
rcu_assign_pointer用于将指针分配给保护数据。此函数使指针可以通过发布以进行对此数据的访问。它将ptr添加到RCU保护结构中,并递增计数器,以指示ptr的替换已发布。如果在此数据的RCU保护期间发布ptr,则将其自动替换为更具体的数据。 如果在此数据的RCU保护期间发布了较旧的指针,则为了安全而不是效率原因,可以从保护期内读取它们,但无法保证它们总是访问有效的指向数据的指针。
3. rcu_dereference()
void *rcu_dereference(pointer);
rcu_dereference用于在RCU保护期间引用数据。如果在RCU保护期间不更改指针,则rcu_dereference返回这个指针。如果在RCU保护期间更改指针并且已发布了该更改,则返回新指针。如果在保护期间曾发布了更具体的数据,则返回该数据。
4.例子
struct my_datap { int a; int b; }; DEFINE_SPINLOCK(datap_lock); struct my_datap *data __read_mostly; void foo(void) { struct my_datap *newp = kmalloc(sizeof(*newp), GFP_KERNEL); if (!newp) return; spin_lock(&datap_lock); *newp = *data; rcu_assign_pointer(data, newp); spin_unlock(&datap_lock); kfree_rcu(data, rcu); } void bar(void) { int sum = 0; struct my_datap *dp = rcu_dereference(data); if (dp) sum = dp->a + dp->b; printk("Sum: %d\n", sum); rcu_barrier(); /*等待访问完成*/ }
在上述示例中,foo函数用于为数据指针data分配新内存,并使用rcu_assign_pointer发布内存分配。另一方面,bar函数使用rcu_dereference用于读取数据指针。最后,rcu_barrier用于确保RCU访问已经完成。此时,新的数据指向新分配的内存。
原创文章,作者:ZQLGJ,如若转载,请注明出处:https://www.506064.com/n/368229.html