在之前的文章中我们已经了解了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
运行结果