在之前的文章中我们已经了解了RCU
机制的原理和Linux的内核源码,这里我们要根据RCU
机制写一个demo来展示他应该如何使用。
RCU机制的原理
-
RCU(全称为Read-Copy-Update),它记录所有指向共享数据的指针的使用者,当要修改构想数据时,首先创建一个副本,并在副本中修改,所哟访问线程都离开读临界区后,使用者的指针指向修改后的副本,并且删除旧数据。
-
他是一种在共享数据结构中实现高效读取和低延迟写入操作的技术。在Linux内核中,RCU是一种基于时间窗口的锁机制,通过充分利用多核处理器和内存系统的特性,在保证并发性的同时提供高性能。
代码示例
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
struct RCUStruct {
int a;
struct rcu_head rcu;
};
static struct RCUStruct* Global_pointer;
static struct task_struct* RCURDThread1, *RCURDThread2, *RCUWTThread;
static int RCURDThreadFunc1(void* argc) {
struct RCUStruct* pointer = NULL;
while(1) {
msleep(5);
rcu_read_lock();
mdelay(10);
pointer = rcu_dereference(Global_pointer);
if(pointer)
printk("%s : read a = %d\n", __func__, pointer->a);
rcu_read_unlock();
}
return 0;
}
static int RCURDThreadFunc2(void* argc) {
struct RCUStruct* pointer = NULL;
while(1) {
msleep(5);
rcu_read_lock();
mdelay(10);
pointer = rcu_dereference(Global_pointer);
if(pointer)
printk("%s : read a = %d\n", __func__, pointer->a);
rcu_read_unlock();
}
return 0;
}
static void MyRCUDel(struct rcu_head* rcuh) {
struct RCUStruct* p = container_of(rcuh, struct RCUStruct, rcu);
printk("%s : a = %d\n", __func__, p->a);
kfree(p);
}
static int RCUWTThreadFunc(void* argc) {
struct RCUStruct* old_pointer;
struct RCUStruct* new_pointer;
int value = (unsigned long)argc;
while(1) {
msleep(10);
new_pointer = kmalloc(sizeof(struct RCUStruct), GFP_KERNEL);
old_pointer = Global_pointer;
*new_pointer = *old_pointer;
new_pointer->a = value;
rcu_assign_pointer(Global_pointer, new_pointer);
call_rcu(&old_pointer->rcu, MyRCUDel);
printk("%s : write to new %d\n", __func__, value);
value++;
}
return 0;
}
static int __init RCUFuncInit(void) {
int value = 2;
printk("Prompt:Successfully initialized the kernel module.\n");
Global_pointer = kzalloc(sizeof(struct RCUStruct), GFP_KERNEL);
RCURDThread1 = kthread_run(RCURDThreadFunc1, NULL, "RCURD1");
RCURDThread2 = kthread_run(RCURDThreadFunc2, NULL, "RCURD2");
RCUWTThread = kthread_run(RCUWTThreadFunc, (void*)(unsigned long)value, "RCUWT");
return 0;
}
static void __exit RCUFuncExit(void) {
printk("Prompt:Successfully uninstalled kernel module!\n");
kthread_stop(RCURDThread1);
kthread_stop(RCURDThread2);
kthread_stop(RCUWTThread);
if(Global_pointer)
kfree(Global_pointer);
}
module_init(RCUFuncInit);
module_exit(RCUFuncExit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lenn louis");
- Makefile
obj-m:=rcu.o
CURRENT_PAHT:=$(shell pwd)
LINUX_KERNEL:=$(shell uname -r)
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) cleals